Jackson多态性:如何将多个子类型映射到同一个类

时间:2013-08-23 04:40:08

标签: java json jackson

我正在使用Jackson 1.9.x. 坚持动物的例子,这就是我想做的事情:

假设我有一个Animal类:

public class Animal {
    private String type;
    // accessors
}

public class Mammal extends Animal {
    private String diet;
    // accessors
}

public class Bird extends Animal {
    private boolean tropical;
    // accessors
}

我希望能够做到这样的事情(我将一些子类型映射到一个类,而将一些子类型映射到另一个类):

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = Mammal.class, name = "Dog"),
                @JsonSubTypes.Type(value = Mammal.class, name = "Cat"),
                @JsonSubTypes.Type(value = Bird.class, name = "Dodo"},
                @JsonSubTypes.Type(value = Bird.class, name = "Cockatoo"})
public class Animal {

}

我现在看到的是杰克逊只会识别狗对哺乳动物和渡渡鸟对鸟的映射。这是因为StdSubtypeResolver._collectAndResolve()只允许同一个类注册一次(由于NamedType.equals()的实现)。

我看到的问题是否有解决方法?

4 个答案:

答案 0 :(得分:3)

也许不是通过使用注释。问题来自于这样的映射不适用于序列化,并且现有映射确实期望一对一(双射)关系。 但您可能希望在jackson-databind issue tracker处提交RFE;可能会增加支持。

答案 1 :(得分:3)

该错误已在 2.6.0 版本中得到解决,因此您只需将Jackson更新为版本 2.6.0 或更高版本。其他信息为herehere

答案 2 :(得分:2)

我也遇到了同样的问题,发现子类型映射需要唯一的类。

我所做的是创建两个扩展相同基类的类。扩展类为空,因为它们具有与基类相同的属性。然后将它们添加到子类型映射中。 例如,在您的情况下,它将是 -

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = Mammal.class, name = "Dog"),
            @JsonSubTypes.Type(value = Mammal.class, name = "Cat"),
            @JsonSubTypes.Type(value = BirdDodo.class, name = "Dodo"},
            @JsonSubTypes.Type(value = BirdCockatoo.class, name = "Cockatoo"})
public class Animal {

}

public class BirdCockatoo extends Cockatoo{}
public class BirdDodo extends Dodo{}

我理解这不是最好的方法,但在问题得不到解决之前,它可能是解决此问题的最佳方法。我现在一直遵循这种方法。

希望它可以帮到你!

答案 3 :(得分:1)

你可以引入一个中级抽象类。

您也可以避免列出整个子类型列表并使用 @JsonTypeName
这个解决方案恕我直言更优雅,因为

  • 定义就在实际的子类型旁边,
  • 冗长的子类型列表使代码的可维护性降低,
  • 您可以在其他地方“插入”类。

操作方法

默认情况下,Jackson 不会遍历类型树来查找嵌套子类型。它会失败:

<块引用>

无法将类型 ID 'Dodo' 解析为
的子类型 ch.zizka.test.Animal: 已知类型 ids = [com.zizka.test.Bird, ... Mammal] ...
在[来源:(字节[])”{

您需要将 @JsonSubTypes 添加到中级类 (Bird, Mammal)。

结果

  • Animal@JsonTypeInfo(use=NAME)
    • Mammal@JsonSubTypes(@Type(Dog.class, Cat.class))
      • Dog@JsonTypeName("Dog")
      • Cat@JsonTypeName("Cat")
    • Bird@JsonSubTypes(@Type(Dodo.class, Cockatoo.class))
      • Dodo@JsonTypeName("Dodo")
      • Cockatoo@JsonTypeName("Cockatoo")

刚刚测试过 - #WORKSFORME。 (杰克逊 2.10.5)