Десериализация вложенного / рекурсивного JSON в объекты Java с наследованием - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть JSON, который является сложным / вложенным.Мой файл JSON состоит из двух эквивалентных Java-объектов.Один - Complex_Expression, а другой - Simple_Expression.Complex_Expression имеет следующую форму:

{
    "SomeOpearator":0,
    "ASpecificKey":1, //the value 1 is fixed for complex expression.
    "Expressions":[ ] //array of one or more expressions
}

Simple Expression имеет следующую форму:

{
    "Operand":"Some String Value",
    "ASpecificKey":0, //the value 0 is fixed for simple expressions.
    "SomeComparisionOpearator":1, // enums which associates int to different comparison operators.
    "Value":["String1"] //this is an array of strings.
}

Expressions в свою очередь может иметь Complex_Expression и / илиSimple_Expression.Файл json всегда начинается с Complex_Expression.Я должен десериализовать этот файл JSON.Моя конечная цель - сделать выражение с использованием объектов Complex_Expression и Simple_Expression и с некоторой логикой в ​​этих классах.Я не против использования jackson или gson или, возможно, других зависимостей.

До сих пор я создал базовый класс с именем Expression.Complex_Expression и Simple_Expression оба наследуют этот класс.Затем я начал писать Custom Json Deserializer.Но в кастомном десериализаторе я застрял и не знаю, как мне поступить.Пожалуйста помоги мне с этим.Мой класс Simple_Expression выглядит следующим образом, и в некоторой степени похож на класс Complex_Expression.

public class Simple_Expression extends Expression
{
    @JsonProperty("Operand") //use jackson deserializer for this class.
    public String Operand;

    @JsonProperty("SomeComparisionOpearator")
    public SomeComparisionOpearator someCompareOperator;

    @JsonProperty("Value")
    public Object value;

    public Simple_Expression()
    {
        super(ASpecificKey.Simple); //Simple corresponds to 0
    }
}

Обновление

Еще немного описания о моем вводе и выводе.С вводом, заданным JSON-строкой, подобной этой:

{
  "SomeOpearator": 0,
  "ASpecificKey": 1,
  "Expressions": [
    {
      "SomeOpearator": 1,
      "ASpecificKey": 1,
      "Expressions": [
        {
          "Operand": "People",
          "ASpecificKey": 0,
          "SomeComparisionOpearator": 14,
          "Value": [
            "Rich"
          ]
        }
      ]
    },
    {
      "SomeOpearator": 1,
      "ASpecificKey": 1,
      "Expressions": [
        {
          "Operand": "Grade",
          "ASpecificKey": 0,
          "SomeComparisionOpearator": 2,
          "Value": [
            "Grade A"
          ]
        }
      ]
    }
  ]
}

Я должен быть в состоянии сделать что-то подобное, предполагая, что десериализатор Джексона:

ObjectMapper mapper = new ObjectMapper();
Expression myExpressionObject = mapper.convertValue(jsonString, Expression.class);

Это должно дать мне десериализованный объект вmyExpressionObject, который будет состоять из списка выражений (Arraylist или Array, без проблем).

1 Ответ

0 голосов
/ 25 сентября 2018

Это было бы легко с добавками Gson RuntimeTypeAdapterFactory, потому что у вас есть поле ASpecificKey, которое можно использовать как дискриминатор типа.См. this для использования.Вы можете просто скопировать исходный код в свой проект, если у вас уже есть Gson.

Я взял на себя смелость исправить ваше соглашение об именах Java, чтобы классы действительно выглядели (а также ваш JSON должен быть исправлен для правильного соглашения):

@Getter @Setter
public class Expression {
    private int aSpecificKey;
}

@Getter @Setter
public class SimpleExpression extends Expression {
    public SimpleExpression() {
        setASpecificKey(0);
    }
    private String operand;
    private int someComparisonOperator;
    private String[] values; 
}

@Getter @Setter
public class ComplexExpression extends Expression {
    public ComplexExpression() {
        setASpecificKey(1);
    }   
    private String someOperator;
    private Expression[] expressions;
}

Против такого рода DTO вы можете просто создать конкретный RuntimeTypeAdapterFactory:

final RuntimeTypeAdapterFactory<Expression> expressionTypeFactory = 
    RuntimeTypeAdapterFactory               
        .of(Expression.class, "aSpecificKey")
        .registerSubtype(SimpleExpression.class, "0")
        .registerSubtype(ComplexExpression.class, "1")

Тогда десериализация будет выглядеть так:

Expression e = getGson(expressionTypeFactory)
        .fromJson(getPackageResourceReader(YOUR_NOTATION_FIXED_JSON),
                                               Expression.class);

Обратите внимание, чтоGson по умолчанию не десериализует дискриминатор типа aSpecificKey, поэтому существуют конструкторы по умолчанию, которые его устанавливают.Если вам это не нужно, вы можете удалить конструкторы по умолчанию.

...