java - 使@JsonTypeInfo 属性可选

标签 java json jackson

我正在使用 @JsonTypeInfo 指示 Jackson 在 @class 属性中查找具体类型信息。但是,有时我不想指定 @class,特别是当可以根据上下文推断出子类型时。 最好的方法是什么?

这是一个 JSON 示例:

{ 
    "owner": {"name":"Dave"},
    "residents":[
        {"@class":"jacksonquestion.Dog","breed":"Greyhound"},
        {"@class":"jacksonquestion.Human","name":"Cheryl"},
        {"@class":"jacksonquestion.Human","name":"Timothy"}
    ]
}

我正在尝试将它们反序列化为这些类(全部在 jacksonquestion.* 中):

public class Household {
    private Human owner;
    private List<Animal> residents;

    public Human getOwner() { return owner; }
    public void setOwner(Human owner) { this.owner = owner; }
    public List<Animal> getResidents() { return residents; }
    public void setResidents(List<Animal> residents) { this.residents = residents; }
}

public class Animal {}

public class Dog extends Animal {
    private String breed;
    public String getBreed() { return breed; }
    public void setBreed(String breed) { this.breed = breed; }
}

public class Human extends Animal {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

使用这个配置:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
private static class AnimalMixin {
}

//...

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.getDeserializationConfig().addMixInAnnotations(Animal.class, AnimalMixin.class);
Household household = objectMapper.readValue(json, Household.class);
System.out.println(household);

如您所见,所有者被声明为人类,而不是动物,因此我希望能够省略 @class 并让 Jackson 像往常一样推断类型。

当我运行它时,我得到了

org.codehaus.jackson.map.JsonMappingException: Unexpected token (END_OBJECT), 
   expected FIELD_NAME: missing property '@class' that is to contain type id  (for class jacksonquestion.Human)

因为“所有者”没有指定@class

有什么想法吗?我最初的一个想法是在属性而不是类型上使用 @JsonTypeInfo但是,这不能用于注释列表的元素类型。(不正确,请参阅答案)

最佳答案

原来我误解了Javadoc for @JsonTypeInfo .当我在我的问题中说

One initial thought I had was to use @JsonTypeInfo on the property rather than the type. However, this cannot be leveraged to annotate the element type of a list.

我是基于 Javadoc 中的这段引述:

When used for properties (fields, methods), this annotation applies to values: so when applied to structure types (like Collection, Map, arrays), will apply to contained values, not the container; for non-structured types there is no difference. (...) There is no per-property way to force type information to be included for type of container (structured type); for container types one has to use annotation for type declaration.

不知何故,我误读了相反的意思;类型信息将应用于容器而不是元素。显然那是错误的。所以我能够使用以下方法解决此问题:

public class Household {
   //...

   @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
   public void setResidents(List<Animal> residents) { 
      this.residents = residents; 
   }
}

现在只有在 residents 属性中指定的 Animals 才需要 @class

关于java - 使@JsonTypeInfo 属性可选,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10905975/

相关文章:

Java:如何计算从时间开始的天数(带时区)

java - 清空最终变量

json - 使用 log4j2 编写自定义 json 消息的最佳方法

python - 使用 python 将 JSON 对象写入文件

json - 如何获取json字段?

java - Jackson 包装器反序列化最佳实践

java - 添加从文本文件读取的 double

java - 为什么用 Guava 创建工厂会出现类型不匹配错误?

json - 如何用自己的JSON转换器替换

java - 如何使用 jackson 将具有 json 值的 Map<String, String> 转换为 POJO?