Java 将@JsonTypeInfo属性设置为可选

Java 将@JsonTypeInfo属性设置为可选,java,json,jackson,Java,Json,Jackson,我使用@JsonTypeInfo指示Jackson在@class属性中查找具体的类型信息。但是,有时我不想必须指定@class,特别是当可以根据上下文推断子类型时最好的方法是什么? 以下是JSON的一个示例: { "owner": {"name":"Dave"}, "residents":[ {"@class":"jacksonquestion.Dog","breed":"Greyhound"}, {"@class":"jacksonquesti

我使用
@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.*
):

如您所见,所有者被声明为人类,而不是动物,因此我希望能够省略
@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
。但是,这不能用于注释列表的元素类型。(不正确,请参见答案)

您可能不应该实际执行此操作——这似乎是针对特殊情况的微观优化,使生活变得复杂——但如果您确实认为您愿意,您可以尝试在Human上添加
@JsonTypeInfo
覆盖。注释在Jackson中是可继承的,您可以覆盖定义。在这种情况下,使用哪一个取决于声明的类型:因此任何声明为
Human
的内容都会在
Human
上看到注释;任何声明为
动物的东西
只有一个在'Animal'中

一个棘手的情况是根值(直接序列化的值):由于没有声明的类型,它将使用运行时类型。这可能不会按你想要的方式工作


另一种可能是子分类
注释Introspector
:您也可以在那里更改
@JsonTypeInfo
的处理方式;看看JacksonAnnotationIntrospector做了什么,在适用的情况下覆盖行为。

所以我误解了。当我在问题中说

我最初的想法是在属性上使用@JsonTypeInfo,而不是在类型上。但是,这不能用于注释列表的元素类型

我是基于Javadoc的这句话:

当用于属性(字段、方法)时,此注释应用于值:因此,当应用于结构类型(如集合、映射、数组)时,将应用于包含的值,而不是容器;对于非结构化类型,没有区别。(…)没有每个属性的方法强制包含容器类型(结构化类型)的类型信息;对于容器类型,必须使用注释进行类型声明

我不知何故误读了这句话,以为它的意思正好相反;类型信息将应用于容器而不是元素。显然这是错误的。因此,我可以通过以下方法解决此问题:

public class Household {
   //...

   @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
   public void setResidents(List<Animal> residents) { 
      this.residents = residents; 
   }
}
公共类家庭{
//...
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS,include=JsonTypeInfo.As.PROPERTY,PROPERTY=“@CLASS”)
公屋居民(名单居民){
这个。居民=居民;
}
}

现在,
@class
仅适用于
居民
属性中指定的动物。

谢谢您的回答。在人类身上覆盖类型是我探索的一条途径,但是(如果我没记错的话)我遇到了我认为你在第二段中描述的问题……当时我试图在
列表中包含
人类
,它抱怨道。我将发布一个关于我如何解决这个问题的答案,但是如果我想继续沿着“可选注释”路径走下去,AnnotationIntrospector看起来是一条有价值的路径。FWIW,这种方式(应用于元素)受到JAXB的严重影响,JAXB具有这种行为。没错,我在上面省略的Javadoc部分包括“这与JAXB处理类型信息注释的方式相同;选择它是因为它是主要的用例。”我同意它是主要的用例。
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)
public class Household {
   //...

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