How to handle Dynamic JSON in Retrofit? How to handle Dynamic JSON in Retrofit? android android

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