杰克逊多态反序列化 - 您是否可以要求存在字段而不是特定值?

Sha*_*aun 14 java polymorphism json jackson deserialization

在动物园示例中使用旋转:

public class ZooPen {
    public String type;
    public List<Animal> animals;
}

public class Animal {
    public String name;
    public int age;
}

public class Bird extends Animal {
    public double wingspan;
}
Run Code Online (Sandbox Code Playgroud)

如果没有指定翼展,我想使用多态反序列化来构造Animal实例,如果是,则使用Bird实例.在Jackson中,无类型反序列化通常看起来像这样:

@JsonTypeInfo( 
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "wingspan",
    visible = true,
    defaultImpl = Animal.class
)
@JsonSubTypes({
    @Type(value = Bird.class, name = **???**)
})  
public class Animal {
    ...
}
Run Code Online (Sandbox Code Playgroud)

翼展值可以是任何东西,如果没有特定匹配的东西,杰克逊会回到defaultImpl类.

我可以使用@JsonCreator

@JsonCreator
public static Animal create(Map<String,Object> jsonMap) 
        throws JsonProcessingException {

    ObjectMapper mapper = new ObjectMapper();
    if (jsonMap.get("wingspan") == null) {
        // Construct and return animal
    } else {
        // Construct and return bird
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我必须手动处理额外的值并抛出一致的异常,并且不清楚Animal是否会在以后正确地序列化.

有没有办法用多态类型处理做我想做的事情?我似乎可以使用自己的TypeResolver或TypeIdResolver,但这似乎比仅仅反序列化原始json更多的工作.或者,可能有一种方法可以定位动物园笔的类型,即使它位于父对象中.有任何想法吗?

编辑:
TypeResolver和TypeIdResolver似乎本质上假设类型信息是序列化的,所以这些不好用.是否可以实现我自己的JsonDeserializer,它挂钩到生命周期来指定类型,但仍然使用基本的jackson注释处理功能?我一直在看JsonDeserializer.deserializeWithType(...),但似乎完全将反序列化委托给TypeDeserializer.还有一个问题是,在我知道要使用哪种类型之前,我需要对某些对象进行反序列化.

M. *_*tin 16

从 Jackson 2.12.2 开始,以下内容使用“基于演绎的多态性”功能实现了目标。如果存在与子类型不同的属性Bird(即wingspan),则反序列化类型将为Bird; 否则将会是Animal

\n
@JsonTypeInfo(use=Id.DEDUCTION, defaultImpl = Animal.class)\n@JsonSubTypes({@Type(Bird.class)})\npublic class Animal {\n    public String name;\n    public int age;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

基于演绎的多态性

\n

基于推导的多态性特征根据与特定子类型不同的属性的存在来推导子类型。如果子类型特定的属性不存在唯一可识别的子类型,defaultImpl则将使用 value 指定的类型。

\n

基于推导的多态性功能是根据Jackson 2.12 中的jackson-databind#43实现的,并在2.12 发行说明中进行了总结:

\n
\n

它基本上允许省略实际的 Type Id 字段或值,只要可以@JsonTypeInfo(use=DEDUCTION)从字段的存在中推导出 ( ) 子类型。也就是说,每个子类型都有一组不同的字段,因此在反序列化期间可以唯一且可靠地检测到类型。

\n
\n

Jackson 2.12.2 中的jackson-databind#3055添加了在没有唯一可识别子类型时指定默认类型 \xe2\x80\x94\xc2\xa0 而不是抛出异常 \xe2\x80\x94\xc2\xa0 的能力:

\n
\n

在没有单一候选人的情况下,defaultImpl无论是否适合,都应该是目标类型。

\n
\n

Jackson 2.12 Most Wanted (1/5)中给出了基于演绎的多态性的稍微长一点的解释:\nJackson创建者撰写的基于演绎的多态性文章。

\n


Jas*_*hal -1

如果您没有与 Jackson 结婚,我相信使用 FlexJSON 可以完成类似的事情。

http://flexjson.sourceforge.net/javadoc/flexjson/JSONDeserializer.html

我不熟悉 Jackson 做类似事情的方法,但我可以说 FlexJSON 非常高效,并且在序列化/反序列化步骤中使用起来通常很直观。