简体   繁体   English

如何使用Gson解析带有递归的对象列表的json?

[英]How to parse json with recursive lists of objects with Gson?

I need to parse incoming json messages to Java Objects using Gson. 我需要使用Gson将传入的json消息解析为Java Objects。 The class "MessageBody" should be used to feed Gson.fromJson(json, MessageBody.class); 应该使用“MessageBody”类来提供Gson.fromJson(json,MessageBody.class);

The json message looks as follows. json消息如下所示。

There are three static fields on the first level. 第一级有三个静态字段。 The third field ("fields") is a list of "DataField"-objects. 第三个字段(“字段”)是“DataField”对象的列表。

A DataField object has a type and a value field. DataField对象具有类型和值字段。 It's value can be heterogeneous. 它的价值可能是异质的。 Expected types are: "String", "int", "boolean" and "HashMap<String, DataField>". 预期的类型是:“String”,“int”,“boolean”和“HashMap <String,DataField>”。

{
    "eventId": "abc",
    "customerId": "abc",
    "fields": {
        "eventDateTime": {
            "type": "datetime",
            "value": "2019-05-03T10:15:30Z"
        },
        "eventCorrelationID": {
            "type": "string",
            "value": "abc"
        },
        "additionalAttributes": {
            "type": "collection",
            "value": {
                "additionalAttribute1": {
                    "value": "abc",
                    "type": "string"
                },
                "additionalAttribute2": {
                    "value": "abc",
                    "type": "string"
                }
            }
        }
    }
}
public class MessageBody {
    private String eventId;
    private String customerId;
    private HashMap<String, DataField> fields;

    public String getEventId() {
        return eventId;
    }

    public void setEventId(String eventId) {
        this.eventId = eventId;
    }

    public String getCustomerId() {
        return customerId;
    }

    public void setCustomerId(String customerId) {
        this.customerId = customerId;
    }

    public HashMap<String, DataField> getFields() {
        return fields;
    }

    public void setFields(HashMap<String, DataField> fields) {
        this.fields = fields;
    }

    public class DataField {
        private Object value;
        private String type;

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            this.value = value;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    }
}

The parsing using the class above works for all objects except of the nested DataField list under "additionalAttributes". 使用上面的类进行解析适用于除“additionalAttributes”下的嵌套DataField列表之外的所有对象。

They result as a LinkedHashTreeMap object. 它们作为LinkedHashTreeMap对象生成。 Unfortunately it's not possible to cast it into another HashMap of DataFields. 不幸的是,它无法将其转换为DataFields的另一个HashMap。

How is it possible to handle nested/recursive lists in heterogenous objects? 如何处理异构对象中的嵌套/递归列表?

How do I get the following statement to work? 如何使以下声明起作用? :-) :-)

HashMap<String, DataField> addAttrs = (HashMap<String, DataField>) messageBody.getFields().get("additionalAttributes").getValue();

Use the structure, hopes it helps: 使用该结构,希望它有所帮助:

 public class MessageBody {
     private String eventId;
     private String customerId;
     private DataFields datafields;

    }

     public class DataFields {
        private DataField eventDateTime;
        private DataField eventCorrelationID;
        pprivate HashMap<String, DataField> additionalAttributes;

     }

    public class DataField {
        private Object value;
        private String type;
    }

You need to implement custom JsonDeserializer . 您需要实现自定义JsonDeserializer You have type information which could be useful to distinguish proper type. 您有类型信息,可用于区分正确的类型。 Below implementation does not use it but you can extend it if you have more than one collection types: 下面的实现不使用它,但如果你有多个集合类型,你可以扩展它:

class DataFieldJsonDeserializer implements JsonDeserializer<DataField> {

    private final Type collectionType = new TypeToken<Map<String, DataField>>() {}.getType();

    @Override
    public DataField deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {
        DataField dataField = new DataField();

        JsonObject jsonObject = json.getAsJsonObject();
        JsonPrimitive type = jsonObject.getAsJsonPrimitive("type");
        dataField.setType(type.getAsString());

        JsonElement value = jsonObject.get("value");
        if (value.isJsonPrimitive()) {
            dataField.setValue(value.getAsJsonPrimitive().getAsString());
        } else {
            Object result = context.deserialize(value, collectionType);
            dataField.setValue(result);
        }

        return dataField;
    }
}

Register adapter: 注册适配器:

@JsonAdapter(DataFieldJsonDeserializer.class)
public static class DataField {

Example usage: 用法示例:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

public class Test {

    public static void main(String[] args) {

        Gson gson = new GsonBuilder().create();
        MessageBody messageBody = gson.fromJson(json, MessageBody.class);

        Map<String, DataField> addAttrs = (Map<String, DataField>) messageBody.getFields()
            .get("additionalAttributes").getValue();
        System.out.println(addAttrs);
    }
}

prints: 打印:

{additionalAttribute1=DataField{value=abc, type='string'}, additionalAttribute2=DataField{value=abc, type='string'}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM