У десериализации Джексона есть максимум для глубины наследования? - PullRequest
1 голос
/ 24 июня 2019

Другими словами, есть ли предел глубины наследования, который может быть достигнут. В настоящее время я на глубине 2, Grandparent -> Parent -> Child, и я столкнулся с проблемой, когда Джексон может десериализоваться до Parent, а затем выбрасывает UnrecognizedPropertyException. Это было бы правильно, однако дочерний класс обладает этим свойством, и я считаю, что я добавил правильную информацию о типе для Джексона, чтобы десериализовать дочерний класс.

Этот тест показывает проблему:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Value;
import lombok.experimental.SuperBuilder;
import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class JacksonInheritanceTest {

    @Test
    public void deserializeChildrenAsGrandParentList() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String grandparentsJson = "{" +
                "\"list\":[{" +
                "\"type\": \"parent\"," +
                "\"value\": \"child\"," +
                "\"someProperty\": \"foobar\"" +
                "}]" +
                "}";
        GrandParentList grandparents = mapper.readValue(grandparentsJson, GrandParentList.class);
        Assert.assertNotNull(grandparents);
    }

    @Test
    public void deserializeParentAsGrandParent() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String parentJson = "{" +
                "\"type\": \"parent\"," +
                "\"value\": \"child\"" +
                "}";
        GrandParent grandparent = mapper.readValue(parentJson, GrandParent.class);
        Assert.assertNotNull(grandparent);
    }

    @Test
    public void deserializeChildAsGrandParent() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String grandparentJson = "{" +
                "\"type\": \"parent\"," +
                "\"value\": \"child\"," +
                "\"someProperty\": \"foobar\"" +
                "}";
        GrandParent grandparent = mapper.readValue(grandparentJson, GrandParent.class);
        Assert.assertNotNull(grandparent);
    }

    @Test
    public void deserializeChildAsParent() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String childJson = "{" +
                "\"type\": \"parent\"," +
                "\"value\": \"child\"," +
                "\"someProperty\": \"foobar\"" +
                "}";
        Parent parent = mapper.readValue(childJson, Parent.class);
        Assert.assertNotNull(parent);
    }

    @Test
    public void deserializeAsChild() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String child1 = "{" +
                "\"type\": \"parent\"," +
                "\"value\": \"child\"," +
                "\"someProperty\": \"foobar\"" +
                "}";
        Child child = mapper.readValue(child1, Child.class);
        Assert.assertNotNull(child);
    }
}

class GrandParentList {
    @JsonProperty
    List<GrandParent> list;
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = Parent.class,
                name = "parent")
})
@Getter
@SuperBuilder
@JsonDeserialize(builder = GrandParent.GrandParentBuilderImpl.class)
class GrandParent {
    @JsonProperty("type")
    private String type;

    @JsonPOJOBuilder(withPrefix = "")
    static final class GrandParentBuilderImpl extends GrandParentBuilder<GrandParent, GrandParent.GrandParentBuilderImpl> {
    }
}


@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "value", visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = Child.class, name = "child")
})
@Getter
@SuperBuilder
@JsonDeserialize(builder = Parent.ParentBuilderImpl.class)
class Parent extends GrandParent {
    @JsonProperty
    private String value;

    @JsonPOJOBuilder(withPrefix = "")
    static final class ParentBuilderImpl extends ParentBuilder<Parent, ParentBuilderImpl> {
    }
}


@EqualsAndHashCode(callSuper = true)
@Value
@SuperBuilder
@JsonDeserialize(builder = Child.ChildBuilderImpl.class)
class Child extends Parent {
    @JsonProperty
    private String someProperty;

    @JsonPOJOBuilder(withPrefix = "")
    static final class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
    }
}

Ответы [ 2 ]

0 голосов
/ 24 июня 2019

Вот как определить наследование со многими уровнями:

Вы хотите десериализовать список GrandParent, конечный тип которого - "child"

  {
      "list":[{
          "type": "child",
          "someProperty": "foobar"
      }]
  }

и дерево наследования:

GrandParent
  Parent
    Child(someProperty:String)

Вы должны определить свой атрибут "type" на верхнем уровне, @JsonTypeInfo (...) Вы можете повторить это на подуровнях, но это не требуется, если вы только сериализуете / десериализуете прародителя. Затем на каждом родительском уровне (классы Parent и GrandParent) вы определяете подтипы так же, как вы это делали с @ JsonSubTypes.

код

public class JacksonInheritanceTest2 {

    @Test
    public void deserializeChildrenAsGrandParentList() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String grandparentsJson = "{" +
                "\"list\":[{" +
                "\"type\": \"child\"," +
                "\"someProperty\": \"foobar\"" +
                "}]" +
                "}";
        GrandParentList grandparents = mapper.readValue(grandparentsJson, GrandParentList.class);
        Assertions.assertNotNull(grandparents);
    }


}

class GrandParentList {
    @JsonProperty
    List<GrandParent> list;
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = Parent.class,name = "parent"),
        //@JsonSubTypes.Type(value = Child.class, name = "child")
})
class GrandParent {
    @JsonProperty("type")
    private String type;

}


//@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = Child.class, name = "child")
})
class Parent extends GrandParent {
    @JsonProperty
    private String value;

}

@JsonSubTypes({
    @JsonSubTypes.Type(value = Child.class, name = "child")
})
class Child extends Parent {
    @JsonProperty
    private String someProperty;

    public String getSomeProperty() {
        return someProperty;
    }

    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }



}

Ошибка, которую вы сделали:

  • определяет множество имен типов атрибутов, каждое для одного родительского уровня: вы выбираете имя типа атрибута и используете только одно.
  • в Json вы установили имя типа родителя в аннотации: важен только тип листа, остальная часть дерева вычитается.

Боковой узел: Assertions от junit5, он делает то же самое, что Assert от junit4

0 голосов
/ 24 июня 2019

Установить конфигурацию объекта ObjectMapper:

mapper.configure (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...