How to handle Dynamic JSON in Retrofit?
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.
RestClient.java
import retrofit.client.Response;public interface RestClient { @GET("/api/foo") Response getYourJson();}
YourClass.java
RestClient restClient;// create your restClientResponse 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.
Try custom deserialisation using gson-converter
as below(updated answer for Retrofit 2.0)
Create three models as shown below
ResponseWrapper
public class ResponseWrapper { @SerializedName("applicationType") @Expose private String applicationType; @SerializedName("responseMessage") @Expose private Object responseMessage; public String getApplicationType() { return applicationType; } public void setApplicationType(String applicationType) { this.applicationType = applicationType; } public Object getResponseMessage() { return responseMessage; } public void setResponseMessage(Object responseMessage) { this.responseMessage = responseMessage; }}
ResponseMessage
public class ResponseMessage extends ResponseWrapper {@SerializedName("surname")@Exposeprivate String surname;@SerializedName("forename")@Exposeprivate String forename;@SerializedName("dob")@Exposeprivate String dob;@SerializedName("refNo")@Exposeprivate String refNo;@SerializedName("result")@Exposeprivate String result;public String getSurname() { return surname;}public void setSurname(String surname) { this.surname = surname;}public String getForename() { return forename;}public void setForename(String forename) { this.forename = forename;}public String getDob() { return dob;}public void setDob(String dob) { this.dob = dob;}public String getRefNo() { return refNo;}public void setRefNo(String refNo) { this.refNo = refNo;}public String getResult() { return result;}public void setResult(String result) { this.result = result;}}
ResponseString
public class ResponseString extends ResponseWrapper {}
UserResponseDeserializer(custom deserialiser)
public class UserResponseDeserializer implements JsonDeserializer<ResponseWrapper> {@Overridepublic ResponseWrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (((JsonObject) json).get("responseMessage") instanceof JsonObject){ return new Gson().fromJson(json, ResponseMessage.class); } else { return new Gson().fromJson(json, ResponseString.class); }}}
Retrofit 2.0 Implementation
Gson userDeserializer = new GsonBuilder().setLenient().registerTypeAdapter(ResponseWrapper.class, new UserResponseDeserializer()).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("base_url") .addConverterFactory(GsonConverterFactory.create(userDeserializer)) .build(); UserService request = retrofit.create(UserService.class); Call<ResponseWrapper> call1=request.listAllUsers(); call1.enqueue(new Callback<ResponseWrapper>() { @Override public void onResponse(Call<ResponseWrapper> call, Response<ResponseWrapper> response) { ResponseWrapper responseWrapper=response.body(); Log.i("DYNAMIC RESPONSE", String.valueOf(response.body().getResponseMessage())); } @Override public void onFailure(Call<ResponseWrapper> call, Throwable t) { } });
Libraries Used
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
***** Previous Answer (above answer is more recommended one) *****
Change your pojo like this
public class TrackerRefResponse { private String applicationType; private Object responseMessage; public Object getResponseMessage() { return responseMessage; } public void setResponseMessage(Object responseMessage) { this.responseMessage = responseMessage; }}
and change retrofit's onResponse like this
@Overridepublic void onResponse(Response<TrackerRefResponse > response) { if (response.isSuccess()) { if (response.getResponseMessage() instanceof String) { handleStringResponse(); } else { handleObjectResponse(); } }}
you may also check this post for more details about dynamic json parsing