0

I don't even know if this is a valid question but I am having a hard time converting the API result to POJO since some key are dynamic.

{
"data": [{
        "something_edit": true
    },
    {
        "test_null": false
    }
],
"success": true

}

As you can see the key inside data are dynamic. I tried using jsonschema2pojo or other converter but it is declaring a named variable which is not a good result. BTW I am using retrofit and GSON library

EDIT:

So here is the flow, so the keys are the ones I asked on the API. So for Example I asked something_edit1, something_edit2 and something_edit3. The data result will be.

{

"data": [{
        "something_edit1": true
    }, {
        "something_edit2": false
    },
    {
        "something_edit3": false
    }
],

"success": true
}
Hanzala
  • 1,965
  • 1
  • 16
  • 43
Androyds
  • 391
  • 1
  • 3
  • 20
  • what i understand from your question. the keys inside data are dynamic like you get the key "something_edit" sometime and sometimes you get the key "test_null" and sometimes both. my question is the keys are getting are confirm like is this confirm that name of the key will be same and will defenetly get some key?? – sourabh kaushik Jan 15 '19 at 05:41
  • is your data variables are predefined or will be declared new any time? like I wrote code for an app in which I got array list of different objects ... so I parsed them by detecting type... so if you have that case then I can help you.... – Hanzala Jan 15 '19 at 05:42
  • @sourabhkaushik yes for your question sometimes the values on data might change based on my request. For example I requested something_edit1, something_edit2, something_edit3 then the data result should be "data": [{"something_edit1": true}, {"something_edit2": false}, {"something_edit3": false}] – Androyds Jan 15 '19 at 05:50
  • @Hanzala please see the Edit – Androyds Jan 15 '19 at 05:57
  • 1
    https://stackoverflow.com/questions/43255577/parse-json-with-unknown-key/43255611#43255611 – IntelliJ Amiya Jan 15 '19 at 06:19
  • have a look on my answer I hope it would be helpful because its working with retrofit – Hanzala Jan 15 '19 at 08:10

3 Answers3

2

You can use Json Object or Generics for your condition.

Using Json Object you can check, if key is exist in your json.

if(yourJsonObject.hasOwnProperty('key_name')){
   // do your work here
}

Using Generic you have to check, if your Pojo have instance of the Pojo.

if(YourMainPOJO instanceOf YourChildPojo){
   // do your work here
}

Try to view only Generic part in this link.

sushildlh
  • 8,986
  • 4
  • 33
  • 77
  • Hi actually I am using retrofit and it will return the Pojo class with data in it thats why I need the pojo to handle it. I get your point that it is easier to just get the response String and modify it based on my requirements. Thanks – Androyds Jan 15 '19 at 05:55
  • @Androyds retrofit return json also. If you want help let me know. I think it might be difficult to handle this dynamic POJO using Objects. – sushildlh Jan 15 '19 at 06:00
1

It's hard to determine or you have to declare all the possible fields in your POJO or write your own json parser extending the Gson Parser or use a JsonElement which can be converted into json array, object and primitive, based on that result you can convert back to some specific pojo.

   /**
 * this will convert the whole json into map which you can use to determine the json elements
 *
 * @param json
 */
private void getModelFromJson(JsonObject json) {
    Gson gson = new Gson();
    Map<String, JsonElement> jsonElementMap = gson.fromJson(json.toString(), new TypeToken<Map<String, JsonElement>>() {
    }.getType());
    for (Map.Entry<String, JsonElement> jsonElementEntry : jsonElementMap.entrySet()) {
        if (jsonElementEntry.getValue().isJsonPrimitive()) {
            //json primitives are data types, do something
            //get json boolean
            //you can here also check if json element has some json object or json array or primitives based on that
            //you can convert this to something else after comparison
            if (true) {
                InterestModelResponse response = gson.fromJson(jsonElementEntry.getValue().getAsJsonObject().toString(), InterestModelResponse.class);
                //use your dynamic converted model
            }
        } else {
            //do something else
        }
    }

}
vikas kumar
  • 10,447
  • 2
  • 46
  • 52
  • I guess for now its either using the response String,create pojo based on response or adding all the keys on POJO. Thanks for clarification. – Androyds Jan 15 '19 at 06:26
1

2 Years ago we did a project in which we had to handle notifications data with different type of objects in same array we handle that while using retrofit

this is our retrofit Creator class

class Creator {
    public static FullTeamService newFullTeamService() {
        final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        final OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .build();

        final Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(FullTeamService.HOST)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create(GsonUtils.get()))
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        return retrofit.create(FullTeamService.class);
    }
}

and GsonUtils.java is:

public class GsonUtils {
    private static final Gson sGson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
        .registerTypeAdapter(NotificationObject.class, new NotificationDeserializer())
        .create();

   private GsonUtils() {}

   public static Gson get() {
    return sGson;
   }
}

NotificationObject is something like:

public class NotificationObject {

@SerializedName("ID")
@Expose
private long ID;

@SerializedName("type")
@Expose
private Type type;

@SerializedName("DataObject")
@Expose
private NotificationDataObject dataObject;

public void setDataObject(NotificationDataObject newsFields) {
    dataObject = newsFields;
}

@SuppressWarnings("unchecked")
public <T> T getDataObject() {
    return (T) dataObject;
}
public enum Type {
    @SerializedName("0")
    CHAT_MESSAGE,
    @SerializedName("10")
    GAME_APPLICATION,
    @SerializedName("20")
    GAME_APPLICATION_RESPONSE,
    @SerializedName("30")
    GAME_INVITE....
}
}

NotificationDataObject as new class is like:

public class NotificationDataObject {}

and finally NotificationDeserializer is like:

public class NotificationDeserializer implements JsonDeserializer<NotificationObject> {
@Override
public NotificationObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    final JsonObject itemBean = json.getAsJsonObject();
    final NotificationObject object = GsonUtils.getSimpleGson().fromJson(itemBean, NotificationObject.class);
    switch (object.getType()) {
        case CHAT_MESSAGE:
            break;
        case GAME_APPLICATION:
            object.setDataObject(GsonUtils.get().fromJson(itemBean.get("DataObject").getAsJsonObject(),
                    GameApplicationNotification.class));
            break;
        case GAME_APPLICATION_RESPONSE:
            object.setDataObject(GsonUtils.get().fromJson(itemBean.get("DataObject").getAsJsonObject(),
                    GameApplicationResponseNotification.class));
            break;
        case GAME_INVITE:
            object.setDataObject(GsonUtils.get().fromJson(itemBean.get("DataObject").getAsJsonObject(),
                    GameInviteNotification.class));
            break;
}
    return object;
}
}

Happy coding ...!

any query will be appreciated...

Hanzala
  • 1,965
  • 1
  • 16
  • 43