使用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的方法