[英]Unable to deserialize complex/dynamic JSON to Java classes using Gson
I've been trying to deserialize a JSON to Java classes using Gson, but the JSON structure is too complex for me to handle. JSON 看起来像这样(由于重复,我已经修剪了一些):
{
"results":[
{
"openEHR-EHR-CLUSTER.encounter_channel.v0/items[at0001]/value<DV_TEXT>":{
"type":"DV_TEXT",
"name":{
"en":"Encounter channel"
},
"attrs":[
"value"
]
},
"openEHR-EHR-CLUSTER.monitoring_reason.v0/items[at0001]/value<DV_TEXT>":{
"type":"DV_TEXT",
"name":{
"en":"Monitoring reason"
},
"attrs":[
"value"
]
}
},
{
"163eee06-83a4-4fd8-bf65-5d6a3ef35ac5":{
"d5760d01-84dd-42b2-8001-a69ebaa4c2df":{
"date":"2020-08-06 09:45:31",
"cols":[
{
"type":"DV_TEXT",
"path":"openEHR-EHR-CLUSTER.encounter_channel.v0/items[at0001]/value<DV_TEXT>",
"values":[
{
"instanceTemplatePath":"prova_de_conceito.en.v1/context/other_context[at0001]/items[archetype_id=openEHR-EHR-CLUSTER.encounter_channel.v0](0)/items[at0001](0)/value",
"value":"null"
}
]
},
{
"type":"DV_TEXT",
"path":"openEHR-EHR-CLUSTER.monitoring_reason.v0/items[at0001]/value<DV_TEXT>",
"values":[
{
"instanceTemplatePath":"prova_de_conceito.en.v1/context/other_context[at0001]/items[archetype_id=openEHR-EHR-CLUSTER.monitoring_reason.v0](1)/items[at0001](0)/value",
"value":"null"
}
]
}
]
},
"fb366b72-d567-4d23-9f5f-356fc09aff6f":{
"date":"2020-08-06 10:02:26",
"cols":[
{
"type":"DV_TEXT",
"path":"openEHR-EHR-CLUSTER.encounter_channel.v0/items[at0001]/value<DV_TEXT>",
"values":[
{
"instanceTemplatePath":"prova_de_conceito.en.v1/context/other_context[at0001]/items[archetype_id=openEHR-EHR-CLUSTER.encounter_channel.v0](0)/items[at0001](0)/value",
"value":"Consulta presencial"
}
]
},
{
"type":"DV_TEXT",
"path":"openEHR-EHR-CLUSTER.monitoring_reason.v0/items[at0001]/value<DV_TEXT>",
"values":[
{
"instanceTemplatePath":"prova_de_conceito.en.v1/context/other_context[at0001]/items[archetype_id=openEHR-EHR-CLUSTER.monitoring_reason.v0](1)/items[at0001](0)/value",
"value":"Consulta"
}
]
}
]
}
}
}
],
"pagination":{
"max":20,
"offset":0,
"nextOffset":20,
"prevOffset":0
},
"timing":"475 ms"
}
主要的JSON object有三个字段: results
, pagination
和timing
。 我可以很好地反序列化pagination
和timing
,因为它们总是具有相同的结构。 我无法正确反序列化results
。
results
始终是两个不同对象的列表。 特别是第二个 object 是最复杂的一个,因为它的字段名称不是 static。 UUID 名称引用总是在每个 API 响应上更改。 例如,名为"163eee06-83a4-4fd8-bf65-5d6a3ef35ac5"
的字段可能在下一个 JSON 响应中具有另一个 id。 因此,我无法在相应的 Java class 中给它一个正确的字段名称。 在这种情况下, "d5760d01-84dd-42b2-8001-a69ebaa4c2df"
和"fb366b72-d567-4d23-9f5f-356fc09aff6f"
也是如此。
关于如何使用 Gson 正确反序列化这种 JSON 的任何想法? 我尝试了几种不同的方法,但到目前为止还没有真正奏效。
在最近的尝试中,我尝试使用 JsonDeserializer 方法来区分results
列表中的对象类型。 我当前的实现看起来像这样(getter 和 setter 因为空间而被隐藏):
查询响应.java
public class QueryResponse {
private List<Map<String, ResultInterface>> results;
private Pagination pagination;
private String timing;
}
分页.java
public class Pagination {
private Integer max;
private Integer offset;
private Integer nextOffset;
private Integer previousOffset;
}
结果接口.java
public interface ResultInterface {
}
元素定义.java
public class ElementDefinition implements ResultInterface {
private String type;
private Name name;
private List<String> attrs;
}
名称.java
public class Name {
private String en;
private String es;
}
作文.java
public class Compositions implements ResultInterface {
private Map<String, Composition> compositions;
}
组成。java
public class Composition {
private String date;
private List<Col> cols;
}
Col.java
public class Col {
private String type;
private String path;
private List<Value> values;
}
值.java
public class Value {
private String instanceTemplatePath;
private String value;
private String magnitude;
private String units;
private String code;
private String terminology_id;
}
ResultInterfaceDeserializer.java
public class ResultInterfaceDeserializer implements JsonDeserializer<ResultInterface> {
@Override
public ResultInterface deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jObject = (JsonObject) json;
JsonElement typeObj = jObject.get("type");
if (typeObj != null) {
return context.deserialize(json, ElementDefinition.class);
} else {
return context.deserialize(json, Compositions.class);
}
}
}
我这样称呼 Gson :
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(ResultInterface.class, new ResultInterfaceDeserializer());
Gson gson = builder.create();
QueryResponse queryResponse = gson.fromJson(externalJsonResponse, QueryResponse.class);
此实现的问题在于 JSON 结构中没有任何命名compositions
,因此没有正确识别Compositions.java
class。 我知道我必须使用 Java 结构,例如Map<String, SomeObject>
,但问题是这里有太多动态命名的 Json 字段,如果它们没有固定的名称标识符,我无法“抓取”它们。
更新
我设法找到了解决方案。 我想说这实际上是一种解决方法,可能不是最干净或优雅的解决方案。 我当前实现的问题是我试图“抓取”一个名为compositions
的 JSON 字段,而实际上它并不存在。 所以,我决定操纵 JSON 并自己添加该字段(在代码中)。 我将解串器 class 更改为:
public class ResultInterfaceDeserializer implements JsonDeserializer<ResultInterface> {
public String encloseJsonWithCompositionsField(JsonElement json) {
return "{\"compositions\":" + json.toString() + "}";
}
@Override
public ResultInterface deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jObject = (JsonObject) json;
if (jObject.get("type") != null) {
return context.deserialize(json, ElementDefinition.class);
} else {
JsonElement jsonWithCompositionsField = new JsonParser().parse(encloseJsonWithCompositionsField(json));
return context.deserialize(jsonWithCompositionsField, Compositions.class);
}
}
}
通过此更改,我现在可以“抓取”组合字段并获取 Java POJO 中的数据。
您可以通过为Compositions
注册一个额外的 JsonDeserializer 来解决这个问题:
public class CompositionsDeserializer implements JsonDeserializer<Compositions> {
public static final CompositionsDeserializer INSTANCE = new CompositionsDeserializer();
private CompositionsDeserializer() { }
@Override
public Compositions deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Compositions compositions = new Compositions();
Map<String, Composition> compositionsMap = new HashMap<>();
compositions.compositions = compositionsMap;
JsonObject compositionsJson = json.getAsJsonObject();
for (Map.Entry<String, JsonElement> compositionEntry : compositionsJson.entrySet()) {
Composition composition = context.deserialize(compositionEntry.getValue(), Composition.class);
compositionsMap.put(compositionEntry.getKey(), composition);
}
return compositions;
}
}
然后在 GsonBuilder 上注册该反序列化器:
Gson gson = new GsonBuilder()
.registerTypeAdapter(ResultInterface.class, new ResultInterfaceDeserializer())
.registerTypeAdapter(Compositions.class, CompositionsDeserializer.INSTANCE)
.create();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.