杰克逊JSON多态性 [英] Jackson JSON Polymorphism

查看:170
本文介绍了杰克逊JSON多态性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试应用 http ://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html )\,并将其应用于我一直致力于的工作。虽然它对我称之为JSON结构中的外部元素非常有用,但我遇到了一个令人沮丧的问题,即没有太多文档。

I've been trying to apply what's on http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html)\, and applying it to what I've been working on. While it works great for what I'll call "outer" elements in the JSON structure, I'm encountering a frustrating problem that there hasn't been much documentation.

首先,我的代码有点如下:

First, my code is somewhat like the following:

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
}

我要做的是在链接博客文章中实现第6个选项,以便JSON显示如下(注意没有'type'元素指定 - 它基于上下文):

What I'm trying to do is to implement the 6th option in the linked blog post so that the JSON will appear like the following (notice no 'type' element specified--it's based off context):

{
    // other properties corresponding to the Parameters object
    "a": {
        "value": "value for a"
    }
}

{
    // other properties corresponding to the Parameters object
    "b": {
        "value": "value for b"
    }
}

我想避免的是引入另一个类型变量int o JSON对象。相反,我更愿意使用上述任何一个JSON示例中提供的上下文来知道我应该根据a或b的存在构建ASubTypeParameters或BSubTypeParameters对象。

What I'm trying to avoid is introducing another "type" variables into the JSON object. Rather, I would prefer to use the context provided into either of the above JSON examples to know that I should be building an ASubTypeParameters or BSubTypeParameters object based on the presence of "a" or "b".

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

The fun thing is that the Parameters class/object is also polymorphic, so I have registered its own custom deserializer class like the following:

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);

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

However, when the above deserializer tries to deserialize either of the above JSON examples, it will get to the part where it tries to deserialize "a" or "b", and indicates that it doesn't know how to handle those properties (UnrecognizedPropretyException if I remove the fail on unknown properties line). My question really boils down to: What am I missing (annotation or otherwise)?

我也尝试添加:

mapper.registerSubtypes(ASubTypeParameters.class, BSubTypeParameters.class)

以及

mapper.registerSubtypes(
    new NamedType(ASubTypeParameters.class, "a"),
    new NamedType(BSubTypeParameters.class, "b")
);

无济于事。

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

I know that I'm getting fairly close, and my guess is that I need to write some sort of custom subtype handler, but the documentation seems to be lacking for what I would like to do (especially when you're deserializing a polymorphic type/class that also contains a polymorphic element).

推荐答案

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

With Jackson you can configure to store the type information as the name of a single field using the following annotation: @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT). The result should look like your JSON example.

我稍微修改了你的代码来证明它:

I have slightly modified your code to demonstrate it:

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));
    }
}

输出:

[ {
  "a" : {
    "value" : "aType"
  }
}, {
  "b" : {
    "value" : "bType"
  }
} ]

这篇关于杰克逊JSON多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆