Как разобрать JSON с рекурсивными списками объектов с помощью Gson? - PullRequest
0 голосов
/ 26 марта 2019

Мне нужно проанализировать входящие сообщения json в объекты Java с помощью Gson. Класс "MessageBody" должен использоваться для подачи Gson.fromJson (json, MessageBody.class);

Сообщение json выглядит следующим образом.

На первом уровне есть три статических поля. Третье поле («поля») представляет собой список объектов «DataField».

Объект DataField имеет поле типа и значения. Это значение может быть неоднородным. Ожидаемые типы: «String», «int», «boolean» и «HashMap ».

{
    "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;
        }
    }
}

Синтаксический анализ с использованием приведенного выше класса работает для всех объектов, кроме вложенного списка DataField в "AdditionalAttributes".

В результате получается объект LinkedHashTreeMap. К сожалению, невозможно преобразовать его в другой HashMap из DataFields.

Как можно обрабатывать вложенные / рекурсивные списки в разнородных объектах?

Как мне заставить работать следующее утверждение? : -)

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

Ответы [ 2 ]

0 голосов
/ 26 марта 2019

Вам нужно реализовать кастом JsonDeserializer. У вас есть информация о типе, которая может быть полезна для определения правильного типа. Ниже реализация не использует его, но вы можете расширить его, если у вас есть несколько типов коллекций:

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;
    }
}

Зарегистрируйте адаптер:

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

Пример использования:

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);
    }
}

печать:

{additionalAttribute1=DataField{value=abc, type='string'}, additionalAttribute2=DataField{value=abc, type='string'}}
0 голосов
/ 26 марта 2019

Используйте структуру, надеется, что это поможет:

 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;
    }
...