使用Jackson和@JsonUnwrapped反序列化多态类型

8

我想做什么

我想使用Jackson来反序列化一个多态类型,使用标准的@JsonTypeInfo注释,如下所示:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, 
              include = As.EXISTING_PROPERTY, 
              property = "identifier")
@JsonSubTypes({@Type(value = A.class, name = "A"),
               @Type(value = B.class, name = "B")})
abstract Class Base {}

Class A implements Base {
    public String identifier = "A";
}

Class B implements Base {
    public String identifier = "B";
}

Class Decorated {
    public String decoration = "DECORATION";

    @JsonUnwrapped
    public Base base;
}

/* 
    Serialized instance of Decorated WITHOUT @JsonUnwrapped:
    {
        "decoration" : "DECORATION",
        "base" : {
            "identifier" : "A"
        }
    }

    Serialized instance of Decorated WITH @JsonUnwrapped:
    {
        "decoration" : "DECORATION",
        "identifier" : "A"
    }
*/

相关文章:使用Jackson将JSON反序列化为多态类型-完整示例出现编译错误

通常可以通过以下方式使用Jackson进行反序列化:

public Object deserialize(String body, Class clazz) {
    ObjectMapper objectMapper = new ObjectMapper();
    return objectMapper.readValue(body, clazz);
}

(如果删除@JsonUnwrapped注释,这将起作用)

问题

多态类型与Jackson的@JsonUnwrapped注释不兼容,这在2012年的Jira票据中讨论过:

http://markmail.org/message/pogcetxja6goycws#query:+page:1+mid:pogcetxja6goycws+state:results

使用 @JsonUnwrapped 处理多态类型 同意 - 尽管修复问题显然更好,但如果无法实现这一点,改进错误消息也会很有用。 展开是其中一个功能,实现变得足够复杂,以至于任何出现的错误(尤其是在反序列化时)都往往具有抗生素耐药性...... 几乎没有鼓励人心。 三年后:

http://markmail.org/message/cyeyc2ousjp72lh3

使用 @JsonUnwrapped 处理多态类型

解决方案:不予修复

该死。

那么,有没有办法在不修改 deserialize() 或移除 @JsonUnwrapped 注释的情况下,让 Jackson 给我提供此行为?


你已经解决了这个问题或找到了变通方法吗? - Dimebag
我没有,你可以始终实现一个自定义序列化器,该序列化器在写入“装饰”字段后将Base的序列化委托给Jackson。 - Zaaier
1个回答

4

我的SinglePolyUnwrappedDeserializer来自于这个代码片段,可以处理单个多态的@JsonUnwrapped属性。它是用Kotlin编写的,但如果需要,可以轻松地转换为Java。例如:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type"
)
@JsonSubTypes(
    JsonSubTypes.Type(value = A::class, name = "a"),
    JsonSubTypes.Type(value = B::class, name = "b")
)
abstract class Base

data class A(val x: Int) : Base()

data class B(val y: Boolean) : Base()

@JsonDeserialize(using = SinglePolyUnwrappedDeserializer::class)
data class C(val a: String, @JsonUnwrapped val b: Base)

据我所知,支持其他注解的所有组合。唯一的限制是只能有一个@JsonUnwrapped属性。
如果您需要针对多态@JsonUnwrapped编写通用序列化程序,则可以很容易地自己编写,而不需要任何反射或内省:只需将内部对象的ObjectNode合并到包含对象的ObjectNode上即可。

你能详细解释一下序列化吗?JsonSerializer具有一个JsonGenerator,因此如何将内部对象序列化为ObjectNode并不清楚? - Tom Quarendon
@TomQuarendon (gen.codec as ObjectMapper).valueToTree<ObjectNode>(inner)(抱歉好几个月没有回答了哈哈。当时我认为这很明显,我只需要反序列化程序) - Anton3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接