使用Retrofit解析动态密钥Json字符串

34

我正在尝试解析以下动态键的Json字符串。

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

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

以下我正试图获取数据,但在解析最后一个动态的JSON字符串时出现错误。

 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;
        }
    }
任何建议如何在这种情况下进行解析!

@Shubh Hai,我也遇到了同样的问题,不知道如何为动态密钥添加Pojo类,你能告诉我在Vitals类中使用了什么吗? - MathankumarK
@MathaN 通过 json 字符串和相应的 Data 类进行检查。报告-> 数据-> 结果-> 生命体征。 因此,生命体征包含 max、min、slope 作为变量。我犯了一个错误,在 Result 中创建了另一个 ResulInside 类,认为它可以将 运行时键生命体征 类映射起来,但实际上并非如此。请查看下面接受的答案,不要创建 ResultInsid,而是直接处理 Result 类本身。 - CoDe
2个回答

67

你的resultInside类添加了一个在JSON中不存在的额外对象层。尝试将地图移动到Data类的results字段。

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

    //....
}

1
在Retrofit中,如果你想解析具有动态键(具有动态名称)的JSON,你肯定需要使用HashMap。所以这个答案是正确的,我给加1分。只需确保将HashMap放在具有静态名称(而不是动态名称)的对象级别上。 - Stoycho Andreev
非常感谢你,你节省了我的时间 :) - aligur
1
如何处理(接收数据),如果每个动态键的其中一个子项是JSONArray of JSONObjects。谢谢 - shehzy
1
你能解释一下为什么这个有效吗?看起来GSON跳过了动态命名的键,但我不明白为什么。 - user1174868

12

更好的方法是:

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

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

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

public class Data {


    public HashMap<String, DataValues> dataValues;


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

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

然后,创建一个像这样的解析器类:

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;
    }


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

之后,在您的 ApiClient 类中键入以下内容

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();

我希望这能帮到某个人


Ruben Caster,这里的DataValues类是什么? - Adrian Ivasku
你可以使用以下信息来创建自己的模型(MODEL):在DATA类中,有一个公共的HashMap<String, DataValues> dataValues;。 - Ruben Caster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接