由于循环依赖,在基类以外的东西上指定 Jackson JSON 子类型

Tod*_*tch 5 java polymorphism json jackson

我们遇到的基本问题是,当存在类型为基类的属性可以是多个子类中的任何一个时,如何处理 JSON 的反序列化。关于这个主题有很多问题,绝大多数似乎都指向基类上 JSONSubTypes 注释的使用。

一般示例如下所示,其中动物可以是多种类型 - 狗、猫、马等.....

public class Pets {

   private List<Animal> myPets;

   public List<Animal> getMyPets(){
        return myPets;
   }

}
Run Code Online (Sandbox Code Playgroud)

埋在注释中的通常是反对每次添加子类时更改基类的要求的注释。考虑以下示例。如果创建了一个“Horse”类并需要使用一个新类型,则需要将一个新类型添加到 Horse 类的 JsonSubTypes 列表中。

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "Dog"),
@JsonSubTypes.Type(value = Cat.class, name = "Cat") }
)
public abstract class Animal {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
Run Code Online (Sandbox Code Playgroud)

这里的问题是如果基类和所有子类不存在于同一个 jar 文件中怎么办?您现在最终会遇到循环依赖。子类依赖于带有基类的 jar 文件,基类依赖于带有子类的 jar。

JAXB 可以通过在属性本身上添加子类列表来处理此问题。类似于以下内容:

   @XmlElements({@XmlElement(name="dog" type=Dog.class),
   @XmlElement(name="cat" type=Cat.class)})
   public List<Animals> getMyPets(){
        return myPets;
   }
Run Code Online (Sandbox Code Playgroud)

无论如何,是否可以使用 Jackson 或不需要将子类型添加到基类的替代解决方案来执行此操作?

Man*_*dis 7

@JsonSubTypes如果您愿意将(部分)类名放入 JSON 而不是您指定的自定义名称,您可以跳过并按名称列出子类型。例如

@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY)
abstract class Animal {
Run Code Online (Sandbox Code Playgroud)

将导致Pets类似的序列化(注意类名前的点):

{"myPets":[{"@c":".Dog","name":"n"},{"@c":".Cat","name":"n"}]}

或者与use = JsonTypeInfo.Id.CLASS您一起获得完整的包裹:

{"myPets":[
{"@class":"com.example.Dog","name":"n"},
{"@class":"com.example.Cat","name":"n" }
]}

检查JsonTypeInfo 的文档

或者,如果 的所有子类Animal都在同一个包中(不同于Animal)并且您ObjectMapper在其中定义,则可以使用 mixins 来指定子类型并避免“循环依赖”:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "Dog"),
@JsonSubTypes.Type(value = Cat.class, name = "Cat") }
)
interface AnimalMixIn {}
Run Code Online (Sandbox Code Playgroud)

mapper.addMixIn(Animal.class, AnimalMixIn.class);
Run Code Online (Sandbox Code Playgroud)

在这种情况下没有@JsonTypeInfo@JsonSubTypesAnimal