如何使用Gson反序列化含动态键的嵌套对象?
如何用Gson解析含动态键名的嵌套JSON?
待解析的示例JSON
[ { "id": "123", "a*": { "b*": { "prio": { "d*": { "id": "234", "name": "test" }, "d1*": { "id": "678", "name": "test1" } } }, "b1*": { "prio": { "d2*": { "id": "234", "name": "test4" } }, "prio": { "d3*": { "id": "234", "name": "test3" } } } }, "a1*": { "b2*": { "prio": { "d5*": { "id": "5435", "name": "test2" }, "d6*": { "id": "675435438", "name": "test15" } } } } }, { "id": "345", "f*": { "g*": { "prio": { "i*": { "id": "5435", "name": "test2" } } } } }, { "id": "342343" } ]
需求说明
- 带星号的键为动态变化键名,实际文件中键可能不含星号
- 嵌套深度不会超过示例,但可能更浅
prio的层级固定,需要获取除prio外的所有键名
最初的尝试代码
尝试用实体类映射的方式解析,但firstMap始终为null:
实体类代码
@Getter @Setter public class PolicyObject { private String id; private Map<String, First> firstMap; @Getter @Setter public class First { private Map<String, Second> secondMap; } @Getter @Setter public class Second { private Map<String, Third> prio; } @Getter @Setter public class Third { private String name; } }
解析逻辑代码
public class mainClass { public void main(InputStreamReader file) { Type typeOfT = TypeToken.getParameterized(PolicyObject.class, clazz).getType(); List<PolicyObject> policies = gson.fromJson(file, typeOfT); } }
解决方法:自定义TypeAdapter
通过自定义TypeAdapter处理动态键名的解析,最终解决了问题:
自定义TypeAdapter代码
public class CustomTypeAdapter extends TypeAdapter<PolicyObject> { private static final String KEY_ID = "id"; private static final String KEY_PRIO = "prio"; private static final String KEY_NAME = "name"; @Override public void write(JsonWriter jsonWriter, PolicyObject policy) throws IOException { } @Override public PolicyObject read(JsonReader reader) throws IOException { PolicyObject policyObject = new PolicyObject(); policyObject.setFirstMap(new HashMap<>()); reader.beginObject(); while (reader.hasNext()) { String firstName = reader.nextName(); if (KEY_ID.equals(firstName)) { policyObject.setId(reader.nextString()); } else { PolicyObject.First first = new PolicyObject.First(); first.setSecondMap(new HashMap<>()); reader.beginObject(); while (reader.hasNext()) { String secondName = reader.nextName(); reader.beginObject(); PolicyObject.Second second = new PolicyObject.Second(); second.setPrio(new HashMap<>()); while (reader.hasNext()) { String prioKey = reader.nextName(); if (KEY_PRIO.equals(prioKey)) { reader.beginObject(); while (reader.hasNext()) { String thirdName = reader.nextName(); reader.beginObject(); PolicyObject.Third rule = new PolicyObject.Third(); while (reader.hasNext()) { String ruleProperty = reader.nextName(); if (KEY_NAME.equals(ruleProperty)) { rule.setName(reader.nextString()); } else { reader.skipValue(); } } second.getPrio().put(thirdName, rule); reader.endObject(); } reader.endObject(); } else { reader.skipValue(); } } first.getSecondMap().put(secondName, second); reader.endObject(); } reader.endObject(); policyObject.getFirstMap().put(firstName, first); } } reader.endObject(); return policyObject; } }
修改后的解析逻辑
public class mainClass { public void main(InputStreamReader file) { Gson gson = new GsonBuilder().registerTypeAdapter(PolicyObject.class, new CustomTypeAdapter()).create(); Type typeOfT = new TypeToken<List<PolicyObject>>() {}.getType(); List<PolicyObject> policies = gson.fromJson(file, typeOfT); } }
内容的提问来源于stack exchange,提问作者Kat
相关产品推荐
相关产品推荐

