Jackson反序列化是否具有最大的继承深度?

时间:2019-06-24 09:46:01

标签: java json jackson

换句话说,可以实现的继承深度是有限的。 目前,我的深度为2,祖父母->父母->孩子,我遇到了一个问题,杰克逊可以反序列化给父母,然后抛出UnrecognizedPropertyException。但这是正确的,但是子类确实拥有该属性,我相信我已经为Jackson添加了正确的Type信息,以反序列化该孩子。

此测试显示了问题:

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 :(得分:0)

在ObjectMapper对象上设置配置:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);

答案 1 :(得分:0)

以下是如何定义具有多个级别的继承:

您要反序列化最终类型为“子级”的GrandParent列表

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

并且继承树是:

GrandParent
  Parent
    Child(someProperty:String)

您必须在顶级@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,它与junit4中的Assert相同