I am using the retrofit efficient networking library, but I am unable to handle Dynamic JSON which contains single prefix responseMessage
which changes to
Late to the party, but you can use a converter.
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://graph.facebook.com")
.setConverter(new DynamicJsonConverter()) // set your static class as converter here
.build();
api = restAdapter.create(FacebookApi.class);
Then you use a static class which implements retrofit's Converter:
static class DynamicJsonConverter implements Converter {
@Override public Object fromBody(TypedInput typedInput, Type type) throws ConversionException {
try {
InputStream in = typedInput.in(); // convert the typedInput to String
String string = fromStream(in);
in.close(); // we are responsible to close the InputStream after use
if (String.class.equals(type)) {
return string;
} else {
return new Gson().fromJson(string, type); // convert to the supplied type, typically Object, JsonObject or Map<String, Object>
}
} catch (Exception e) { // a lot may happen here, whatever happens
throw new ConversionException(e); // wrap it into ConversionException so retrofit can process it
}
}
@Override public TypedOutput toBody(Object object) { // not required
return null;
}
private static String fromStream(InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append("\r\n");
}
return out.toString();
}
}
I have written this sample converter so it returns the Json response either as String, Object, JsonObject or Map< String, Object >. Obviously not all return types will work for every Json, and there is sure room for improvement. But it demonstrates how to use a Converter to convert almost any response to dynamic Json.
I know I am late, but I just want to share my thought. I was working on a project where I am writing a method. The method uses retrofit to get data from server. Since other developers in my company will use this method, I could not use a POJO
class (in your example, the TrackerRefResponse
class). So I used JsonObject
/ Object
like this:
public class APIService{
@FormUrlEncoded
@POST
Call<JsonObject> myPostMethod(@Url String url, @Field("input") String input);
}
Then in my method, I wrote this:
Call<JsonObject> call = RetrofitClient.getAPIService().establishUserSession(post_request_url, someParameter);
call.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
JsonObject jsonObject = response.body();
String jsonString = response.body().toString();
// then do your stuff. maybe cast to object using a factory pattern
}
// rest of the code
}
You can also use Object
instead of 'JsonObject`. Later, when you will know which kind of response it is, maybe you can cast this into desired object.
RestClient.java
import retrofit.client.Response;
public interface RestClient {
@GET("/api/foo") Response getYourJson();
}
YourClass.java
RestClient restClient;
// create your restClient
Response response = restClient.getYourJson();
Gson gson = new Gson();
String json = response.getBody().toString();
if (checkResponseMessage(json)) {
Pojo1 pojo1 = gson.fromJson(json, Pojo1.class);
} else {
Pojo2 pojo2 = gson.fromJson(json, Pojo2.class);
}
You must implement "checkResponseMessage" method.
Any of your possible solutions will work. What you can also do is send the Retrofit api interface return type to response. With that response you get a body Inputstream
which you can convert to a JSON Object and read as you see fit.
Look at: http://square.github.io/retrofit/#api-declaration - under RESPONSE OBJECT TYPE
Updated
Retrofit 2 is out now and with it some changes to the documentation and library.
Look at http://square.github.io/retrofit/#restadapter-configuration there are request and response body object that can be used.