Jackson JSON 多态性

Mik*_*ugh 5 json jackson

我一直在尝试应用http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html )\上的内容,并将其应用到我一直在做的事情中。虽然它非常适合我所说的 JSON 结构中的“外部”元素,但我遇到了一个令人沮丧的问题,即没有太多文档。

首先,我的代码有点像下面这样:

interface Parameters {
    // Couple random properties -- no problem here

    SubTypeParameters getSubTypeParameters(); // where SubTypeParameters are polymorphic
    void setSubTypeParameters(SubTypeParameters value);
}

@JsonSubTypes({
    @JsonSubTypes.Type(name = "a", value = ASubTypeParameters.class),
    @JsonSubTypes.Type(name = "b", value = BSubTypeParameters.class)
})
interface SubTypeParameters {
    String getValue();
    void setValue(String value);
}

@JsonTypeName(value = "a")
class ASubTypeParameters implements SubTypeParameters {
    // getter/setter implemented
}

@JsonTypeName(value = "b")
class BSubTypeParameters implements SubTypeParameters {
    // getter/setter implemented
}
Run Code Online (Sandbox Code Playgroud)

我想做的是实现链接博客文章中的第六个选项,以便 JSON 将如下所示(注意没有指定“type”元素 - 它基于上下文):

{
    // other properties corresponding to the Parameters object
    "a": {
        "value": "value for a"
    }
}
Run Code Online (Sandbox Code Playgroud)

或者

{
    // other properties corresponding to the Parameters object
    "b": {
        "value": "value for b"
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图避免的是在 JSON 对象中引入另一个“类型”变量。相反,我更愿意使用上述 JSON 示例中提供的上下文来知道我应该基于“a”或“b”的存在构建 ASubTypeParameters 或 BSubTypeParameters 对象。

有趣的是,Parameters 类/对象也是多态的,因此我注册了自己的自定义反序列化器类,如下所示:

ObjectMapper mapper = new ObjectMapper();
StdDeserializer<Parameters> parameterDeserializer = new ParameterDeserializer();
SimpleModule module = new SimpleModule ( ... ); // simplifying this--no problem here
module.addDeserializer(Parameters.class, parameterDeserializer);
mapper.registerModule(module);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Run Code Online (Sandbox Code Playgroud)

但是,当上面的反序列化器尝试反序列化上述 JSON 示例中的任何一个时,它将到达尝试反序列化“a”或“b”的部分,并指示它不知道如何处理这些属性(UnrecognizedPropretyException如果我删除未知属性行上的失败)。我的问题实际上可以归结为:我缺少什么(注释或其他)?

我也尝试添加:

mapper.registerSubtypes(ASubTypeParameters.class, BSubTypeParameters.class)
Run Code Online (Sandbox Code Playgroud)

mapper.registerSubtypes(
    new NamedType(ASubTypeParameters.class, "a"),
    new NamedType(BSubTypeParameters.class, "b")
);
Run Code Online (Sandbox Code Playgroud)

无济于事。

我知道我已经相当接近了,我的猜测是我需要编写某种自定义子类型处理程序,但文档似乎缺少我想要做的事情(特别是当您反序列化多态类型时) /class 也包含多态元素)。

Ale*_*lov 3

使用 Jackson,您可以使用以下注释将类型信息存储为单个字段的名称:@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)。结果应该类似于您的 JSON 示例。

我稍微修改了您的代码来演示它:

public class JacksonPolymorphic2 {
    @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
    @JsonSubTypes({
            @JsonSubTypes.Type(name = "a", value = ASubTypeParameters.class),
            @JsonSubTypes.Type(name = "b", value = BSubTypeParameters.class)
    })
    interface SubTypeParameters {
        String getValue();
        void setValue(String value);
    }

    @JsonTypeName(value = "a")
    static class ASubTypeParameters implements SubTypeParameters {
        ASubTypeParameters(String value) {
            this.value = value;
        }

        private String value;
        @Override
        public String getValue() {
            return value;
        }

        @Override
        public void setValue(String value) {
            this.value = value;
        }
    }

    @JsonTypeName(value = "b")
    static class BSubTypeParameters implements SubTypeParameters {
        BSubTypeParameters(String value) {
            this.value = value;
        }

        private String value;
        @Override
        public String getValue() {
            return value;
        }

        @Override
        public void setValue(String value) {
            this.value = value;
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        ASubTypeParameters a = new ASubTypeParameters("aType");
        BSubTypeParameters b = new BSubTypeParameters("bType");
        List<? super SubTypeParameters> list = new ArrayList<>();
        list.add(a);
        list.add(b);

        ObjectMapper mapper = new ObjectMapper();
        System.out.printf(mapper
                .writerWithType(new TypeReference<List<SubTypeParameters>>() {})
                .withDefaultPrettyPrinter()
                .writeValueAsString(list));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

[ {
  "a" : {
    "value" : "aType"
  }
}, {
  "b" : {
    "value" : "bType"
  }
} ]
Run Code Online (Sandbox Code Playgroud)