Сериализация и десериализация древовидной структуры с Джексоном - PullRequest
1 голос
/ 15 февраля 2020

У меня есть древовидная структура со следующими объектами, которые мне нужны для сериализации и десериализации с использованием Джексона, но я не могу понять, как это сделать.

Type

Type имеет имя и версия. Он также может иметь родительский и подтипы.

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name")
final class Type {

    private final PrefixedName name;
    private final Integer version;
    private final Set<Type> subTypes = new HashSet<>();
    private final Type parent;
    private final PrefixedName parentName;


    Type(final PrefixedName name, final Integer version) {
        this(name, version, null);
    }

    @JsonCreator
    Type(@JsonProperty("name") @JsonDeserialize(keyUsing = PrefixedNameKeyDeserializer.class) final PrefixedName name,
            @JsonProperty("typeVersion") final Integer version, @JsonProperty("parent") final Type parent) {
        this.name = Objects.requireNonNull(name);

        Preconditions.checkArgument(version > 0, "Version number must be positive");
        this.version = version;

        this.parent = parent;
        if (parent != null) {
            this.parentName = parent.getName();
            parent.addSubType(this);
        } else {
            this.parentName = null;
        }
    }

    // Other methods to add sub-types; and getters for all properties omitted

}

Model

Model содержит root дерева - Type и версию.

final class Model {

    private final Integer version;
    private final Type root;

    @JsonCreator
    Model(@JsonProperty("modelVersion") final Integer version, @JsonProperty("root") final Type root) {
        this.version = version;
        this.root = root;
    }

При использовании ObjectMapper Джексона сериализация выглядит так, как я и ожидал:

{
   "root":{
      "parent":null,
      "name":{
         "localName":"Base",
         "prefix":"schema"
      },
      "subTypes":[
         {
            "parent":{
               "localName":"Base",
               "prefix":"schema"
            },
            "name":{
               "localName":"Person",
               "prefix":"schema"
            },
            "subTypes":[
               {
                  "parent":{
                     "localName":"Person",
                     "prefix":"schema"
                  },
                  "name":{
                     "localName":"employee",
                     "prefix":"schema"
                  },
                  "subTypes":[

                  ],
                  "version":1
               }
            ],
            "version":1
         },
         {
            "parent":{
               "localName":"Base",
               "prefix":"schema"
            },
            "name":{
               "localName":"organisation",
               "prefix":"schema"
            },
            "subTypes":[

            ],
            "version":1
         },
         {
            "parent":{
               "localName":"Base",
               "prefix":"schema"
            },
            "name":{
               "localName":"CreativeWork",
               "prefix":"schema"
            },
            "subTypes":[
               {
                  "parent":{
                     "localName":"CreativeWork",
                     "prefix":"schema"
                  },
                  "name":{
                     "localName":"Journal",
                     "prefix":"schema"
                  },
                  "subTypes":[

                  ],
                  "version":1
               },
               {
                  "parent":{
                     "localName":"CreativeWork",
                     "prefix":"schema"
                  },
                  "name":{
                     "localName":"Book",
                     "prefix":"schema"
                  },
                  "subTypes":[

                  ],
                  "version":1
               }
            ],
            "version":1
         }
      ],
      "version":1
   },
   "version":8
}

Обратите внимание, аннотация класса Type @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name") означает, что свойство parent записывается с использованием только свойства name - это предотвращает бесконечную рекурсию, а StackOverflowException - если есть лучший способ сделать это, я был бы рад изменить.

Однако десериализация терпит неудачу с NullPointerException в строке, устанавливающей свойство name в Type:

this.name = Objects.requireNonNull(name);

Я отлаживал код и видел, что Джексон захватывает два свойства PrefixedName (класс показано ниже) для родителя как «неизвестные» свойства - я не уверен, связано ли это с проблемой, но это может быть полезно.

PrefixedName

Это просто AutoValue класс двух свойств String с аннотациями Джексона:

@AutoValue
@SuppressWarnings("squid:S1610")
@JsonDeserialize(builder = AutoValue_PrefixedName.Builder.class)
abstract class PrefixedName {

    static Builder builder() {
        return new AutoValue_PrefixedName.Builder();
    }

    @JsonProperty
    abstract String prefix();

    @JsonProperty
    abstract String localName();

    @AutoValue.Builder
    abstract static class Builder {

        @JsonProperty
        abstract Builder prefix(final String prefix);

        @JsonProperty
        abstract Builder localName(final String localName);

        abstract PrefixedName build();
    }
}

Спасибо за любую помощь, которую вы можете предложить.

...