使用Gson解析含有动态未知键名的json数据

初学Android开发,最近在开发一个用来练手的android小项目,遇到了一个问题:在解析json时遇到了含有未知字段的json数据,此时不能通过Gson库的静态解析方式进行解析。文档上提到了可以自定义解析器,网上也有一些类似的实现案例。我也记录下相应的解决方案。

我获取的json数据可简化为:

// news
{
    news_id: "id",
    news_title: "title"
}
// monthJson
{
    "2017-09-05": [
        {
            news_id: "id1",
            news_title: "title1"
        },
        {
            news_id: "id2",
            news_title: "title2"
        }
    ],
    "2017-09-04": [
        {
            news_id: "id1",
            news_title: "title1"
        },
        {
            news_id: "id2",
            news_title: "title2"
        }
    ]
}

可建立如下模型(省略 getter 和 setter ):

public class News {
    @SerializedName("news_id")
    private String id;
    @SerializedName("news_title")
    private String title;
}

public class MonthNews {
    private Map<String, List<News>> monthNews;

    public MonthNews(Map<String, List<News>> monthNews) {
        this.monthNews = monthNews;
    }

    public Map<String, List<News>> getMonthNews() {
        return monthNews;
    }
}

通过注册自定义的解析器进行解析:

JSONObject jsonObject = new JSONObject(monthJson);
Gson gson = new Gson();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MonthNews.class, new JsonDeserializer<MonthNews>() {
    @Override
    public MonthNews deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();
        Map<String, List<News>> month = new LinkedHashTreeMap<>();
        for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
            List<News> day = context.deserialize(entry.getValue(), new TypeToken<List<News>>(){}.getType());
            month.put(entry.getKey(), day);
        }
        return new MonthNews(monthNews);
    }
});
gson = builder.setFieldNamingPolicy(LOWER_CASE_WITH_UNDERSCORES).create();
MonthNews monthNews = gson.fromJson(jsonObject.toString(), MonthNews.class);

其实我觉得在这个场景下,不使用gson的自定义解析器而直接通过JSONObject进行解析显得更方便:

JSONObject jsonObject = new JSONObject(monthJson);
Gson gson = new Gson();
Map<String, List<News>> month = new LinkedHashTreeMap<>();
JSONArray names = jsonObject.names();
for (int i = 0; i < names.length(); i++) {
    String day = jsonObject.getString(names.getString(i));
    news = gson.fromJson(day, new TypeToken<List<News>>(){}.getType());
    month.put(names.getString(i), news);
}
MonthNews monthNews = new MonthNews(month);

两种方式归根到底都是通过Map得到了变化的key, 效率方面应该没有什么明显区别。

参考链接 GitHub: Gson Dealing with randomly generated and inconsistent JSON field/key names using GSON How to decode JSON with unknown field using Gson? Gson解析JSON中动态未知字段key的方法

comments powered by Disqus