34

I'm trying to parse following dynamic key Json String.

"report":{
    "data":{
        "results":{
            "558952cca6d73d7d81c2eb9d":{
                "Max":-1,
                "Min":-1,
                "Slope":-1,
            },

            "558ce148a6d73d7d81c2fa8a":{
                "Max":-2,
                "Min":-1,
                "Slope":-2,
            }
        }
    }
}

Following I'm trying to get data, but getting error while parse last dynamic json String.

 public class Report {
        @SerializedName("data")
        @Expose
        private Data data;

        public Data getData() {
            return data;
        }

        public void setData(Data data) {
            this.data = data;
        }

        @Override
        public String toString() {
            return "Report{" +
                    "data=" + data +
                    '}';
        }
    }

    public class Data {
        @SerializedName("results")
        @Expose
        private ResultInside result;

        public ResultInside getResult() {
            return result;
        }

        public void setResult(ResultInside result) {
            this.result = result;
        }
    }

    public class ResultInside {
        /*@SerializedName("results")
        @Expose*/
        private Map<String, Vitals> elemDetails = new HashMap<>();

        public Map<String, Vitals> getElemDetails() {
            return elemDetails;
        }

        public void setElemDetails(Map<String, Vitals> elemDetails) {
            this.elemDetails = elemDetails;
        }
    }

Any suggestion how to parse in this case !

2
  • @Shubh Hai, I am having the same issue, I don't know how to add Pojo class for Dynamic Key, Can you tell what you have used in Vitals Class? Commented Apr 19, 2016 at 11:59
  • @MathaN check with json string and respected Data class. Report -> Data -> results -> Vitals. And so vital contain max, min, slope as variable. I did mistake to Create another ResulInside class inside Result with thought, it will map runtime Key with Vitals class but that is not the case. Check accepted answer below, instead to create ResultInsid handle it Result class itself. Commented Apr 19, 2016 at 14:12

2 Answers 2

68

Your resultInside class is adding an extra object layer that does not exist in your JSON. Try moving the map to your Data class results field.

public class Data {
    @SerializedName("results")
    @Expose
    private Map<String, Vitals> result;

    //....
}
Sign up to request clarification or add additional context in comments.

3 Comments

In retrofit if you want to parse JSON with dynamic keys (with dynamic names) you need to use HashMap for sure. So this answer is the correct one +1 from me. Just make sure you are putting you HashMap on object level which has static name (not dynamic name)
How to handle(receive data from) the situation if one of children of each dynamic key is JSONArray of JSONObjects. Thanks
Can you explain why this works? It looks like GSON is skipping the dynamically named key but I don't understand why.
12

A better way to do this, would be:

----------------------

public class Report {
        @SerializedName("data")
        @Expose
        private Data data;

----------------------

public class Data {


    public HashMap<String, DataValues> dataValues;


    public Data() {
        this.dataVaues = new HashMap<>();
    }
}

-----------------------------

then, create a Parser class like this:

public class DataParser implements JsonDeserializer<Data> {


    @Override
    public Data deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        Data result = new Data();


        try {
            final HashMap<String, DataValues> map = readServiceUrlMap(json.getAsJsonObject());

            if(map != null) {
                result.dataValues = map;
            }

        }catch (JsonSyntaxException ex){
            return null;
        }

        return result;
    }


    private HashMap<String, DataValues> readServiceUrlMap(final JsonObject jsonObject) throws JsonSyntaxException {

        if(jsonObject == null) {
            return null;
        }
        Gson gson = new Gson();

        HashMap<String, DataValues> products = new HashMap<>();

        for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {

            String key = entry.getKey();
            DataValues value = gson.fromJson(entry.getValue(), DataValues.class);
            products.put(key, value);
        }
        return products;
    }


----------------------------------------------

after that, type this in your ApiClient class

public class ApiClient {


    private static Retrofit retrofit = null;

    public static Retrofit getClient(String baseUrl) {

        if(retrofit == null) {

            GsonBuilder gsonBuilder = new GsonBuilder();
            gsonBuilder.registerTypeAdapter(Data.class, new DataParser());

            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()))
                    .build();

I hope this will help someone

2 Comments

Ruben Caster, what is DataValues class here ?
your own model with use case info (the class inside DATA -> public HashMap<String, DataValues> dataValues;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.