由于循环依赖性而在基类之外的其他内容上指定Jackson JSON子类型

时间:2018-03-07 14:00:55

标签: java json jackson polymorphism

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

一般的例子如下,其中动物可以是几种类型 - 狗,猫,马等......

public class Pets {

   private List<Animal> myPets;

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

}

在评论中埋葬通常是一个评论,反对每次添加子类时更改基类的要求。请考虑以下示例。如果创建了一个“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;
    }

}

如果基类和所有子类不在同一个jar文件中,那么这里的问题是什么?您现在最终得到循环依赖。子类依赖于具有基类的jar文件,并且基类依赖于具有子类的jar。

JAXB有一种方法可以通过在属性本身上添加子类列表来处理这个问题。如下所示:

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

无论如何,杰克逊还是不需要将子类型添加到基类的替代解决方案吗?

1 个答案:

答案 0 :(得分:2)

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

@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY)
abstract class Animal {

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

  

{ “myPets”:[{ “@ C”: “犬”, “姓名”: “N”},{ “@ C”: “名称”, “目录”: “N”}]}

use = JsonTypeInfo.Id.CLASS您也可以获得完整的套餐:

  

{ “myPets”:[
       { “@class”: “com.example.Dog”, “名”: “N”},
       { “@class”: “com.example.Cat”, “名”: “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 {}

mapper.addMixIn(Animal.class, AnimalMixIn.class);

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