有没有一种方法可以通过在Jackson中包含数组来确定抽象对象的目标类型?

时间:2018-09-04 14:07:28

标签: java jackson

我有以下类,必须将其序列化为JSON并返回到该类实例:

public class Container {

    private List<Base> derivedOne;
    private List<Base> derivedTwo;

    @JsonCreator
    public Container(@JsonProperty("derivedOne") List<Base> derivedOne, 
                     @JsonProperty("derivedTwo") List<Base> derivedTwo) {
        this.derivedOne = derivedOne;
        this.derivedTwo = derivedTwo;
    }

    public static class Derived1 extends Base {

        private String derivedField1;

        public Derived1(String derivedField1) {
            this.derivedField1 = derivedField1;
        }
    }

    public static class Derived2 extends Base {

        private String derivedField2;

        public Derived2(String derivedField2) {
            this.derivedField2 = derivedField2;
        }
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = 
                  JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({
        @JsonSubTypes.Type(value = Derived1.class, name = "one"),
        @JsonSubTypes.Type(value = Derived2.class, name = "two")
    })
    public abstract static class Base {
    }

}

这样derivedOne容器将只保留Derived1.class实例,而derivedTwo-仅保留Derived2.class实例。

Jackson中是否有一种方法不使用额外的type属性,而是通过包含的容器名称来确定目标类?

我试图使其与自定义TypeIdResolver一起使用,但没有成功。

1 个答案:

答案 0 :(得分:2)

取决于您的json值。

您可以使用 type 表示反序列化的类型。

下面是完整的代码。

public class Container {

    private List<Base> derivedOne;
    private List<Base> derivedTwo;

    @JsonCreator
    public Container(@JsonProperty("derivedOne") List<Base> derivedOne,
                     @JsonProperty("derivedTwo") List<Base> derivedTwo) {
        this.derivedOne = derivedOne;
        this.derivedTwo = derivedTwo;
    }

    public static class Derived1 extends Base {

        private String derivedField1;

        public String getDerivedField1() {
            return derivedField1;
        }

        public void setDerivedField1(String derivedField1) {
            this.derivedField1 = derivedField1;
        }
    }

    public static class Derived2 extends Base {

        private String derivedField2;

        public String getDerivedField2() {
            return derivedField2;
        }

        public void setDerivedField2(String derivedField2) {
            this.derivedField2 = derivedField2;
        }
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include =
            JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({
            @JsonSubTypes.Type(value = Derived1.class, name = "one"),
            @JsonSubTypes.Type(value = Derived2.class, name = "two")
    })
    public abstract static class Base {
    }

    public static void main(String[] args) throws IOException {

        String jsonStr = "{\"derivedOne\":[{\"type\":\"one\",\"derivedField1\":\"derivedField1\"},{\"type\":\"two\",\"derivedField2\":\"derivedField2\"}],\"derivedTwo\":[{\"type\":\"one\",\"derivedField1\":\"derivedField1\"},{\"type\":\"two\",\"derivedField2\":\"derivedField2\"}]}";

        ObjectMapper objectMapper = new ObjectMapper();
        Container container = objectMapper.readValue(jsonStr, Container.class);
    }
}

使用@JsonTypeIdResolver

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include =
            JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonTypeIdResolver(ContainerResolver.class)
    public abstract static class Base {
    }

    public static void main(String[] args) throws IOException {

        String jsonStr = "{\"derivedOne\":[{\"type\":\"one\",\"derivedField1\":\"derivedField1\"},{\"type\":\"two\",\"derivedField2\":\"derivedField2\"}],\"derivedTwo\":[{\"type\":\"one\",\"derivedField1\":\"derivedField1\"},{\"type\":\"two\",\"derivedField2\":\"derivedField2\"}]}";

        ObjectMapper objectMapper = new ObjectMapper();
        Container container = objectMapper.readValue(jsonStr, Container.class);
    }


public class ContainerResolver extends TypeIdResolverBase {

    private JavaType superType;

    @Override
    public void init(JavaType baseType) {
        this.superType = baseType;
    }

    @Override
    public String idFromValue(Object value) {
        return idFromValueAndType(value, value.getClass());
    }

    @Override
    public String idFromValueAndType(Object value, Class<?> suggestedType) {

        String typeId = null;
        switch (suggestedType.getSimpleName()) {
            case "Derived1":
                typeId = "one";
                break;
            case "Derived2":
                typeId = "two";
        }
        return typeId;
    }

    @Override
    public JavaType typeFromId(DatabindContext context, String id)  throws IOException {

        Class<?> subType = null;
        switch (id) {
            case "one":
                subType = Container.Derived1.class;
                break;
            case "two":
                subType = Container.Derived2.class;
        }
        return context.constructSpecializedType(superType, subType);
    }

    @Override
    public JsonTypeInfo.Id getMechanism() {
        return JsonTypeInfo.Id.NAME;
    }
}

This文章可能对您有所帮助。