问题原因
json反序列化为接口(抽象类)时,同时该接口(抽象类)有多个实现(继承)时,jackson不知道反序列化为哪个子类对象。
报错信息
Can not construct instance of XXXX, problem: ``abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
这个报错很容易和没有无参构造器的混淆。
解决方法
通过注解@JsonTypeInfo和@JsonSubtypes,指定反序列化为子类的规则。
@JsonTypeInfo
use:定义使用哪一种类型识别码,它有下面几个可选值:
1、JsonTypeInfo.Id.CLASS:使用完全限定类名做识别
2、JsonTypeInfo.Id.MINIMAL_CLASS:若基类和子类在同一包类,使用类名(忽略包名)作为识别码
3、JsonTypeInfo.Id.NAME:一个合乎逻辑的指定名称
4、JsonTypeInfo.Id.CUSTOM:自定义识别码
5、JsonTypeInfo.Id.NONE:不使用识别码
include(可选):指定识别码是如何被包含进去的,它有下面几个可选值:
1、JsonTypeInfo.As.PROPERTY:作为数据的兄弟属性
2、JsonTypeInfo.As.EXISTING_PROPERTY:作为POJO中已经存在的属性
3、JsonTypeInfo.As.EXTERNAL_PROPERTY:作为扩展属性
4、JsonTypeInfo.As.WRAPPER_OBJECT:作为一个包装的对象
5、JsonTypeInfo.As.WRAPPER_ARRAY:作为一个包装的数组
property(可选):制定识别码的属性名称
此属性只有当use为
JsonTypeInfo.Id.CLASS(若不指定property则默认为@class)
JsonTypeInfo.Id.MINIMAL_CLASS(若不指定property则默认为@c)
JsonTypeInfo.Id.NAME(若不指定property默认为@type)
include为JsonTypeInfo.As.PROPERTY、JsonTypeInfo.As.EXISTING_PROPERTY、JsonTypeInfo.As.EXTERNAL_PROPERTY时才有效
defaultImpl(可选):如果类型识别码不存在或者无效,可以使用该属性来制定反序列化时使用的默认类型
visible(可选,默认为false):propery中的属性是否反序列化到POJO中<br> 属性定义了类型标识符的值是否会通过JSON流成为反序列化器的一部分,默认为fale,也就是说,jackson会从JSON内容中处理和删除类型标识符再传递给JsonDeserializer
@JsonSubtypes
作用于类/接口,用来列出给定类的子类,只有当子类类型无法被检测到时才会使用它。一般是配合@JsonTypeInfo在基类上使用,比如:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.EXISTING_PROPERTY ,property = "contentType", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = MessageContentBack.class, name = "text/plain"),
@JsonSubTypes.Type(value = MessageContentFile.class, name = "application/vnd.gsma.rcs-ft-http"),
@JsonSubTypes.Type(value = MessageContentReceiveResponse.class, name = "application/vnd.gsma.botsuggestion.response.v1.0+json"),
@JsonSubTypes.Type(value = MessageContentSharedData.class, name = "application/vnd.gsma.botsharedclientdata.v1.0+json"),
})
使用实例
示例1
@JsonTypeInfo(use = JsonTypeInfo.Id.*CLASS*, include = JsonTypeInfo.As.*PROPERTY*, property = “@clazz”)
@JsonSubTypes({
@JsonSubTypes.Type(value = Terms4AccuracyLevelVo.class, name = “AccuracyLevel”),
@JsonSubTypes.Type(value = Terms4AnswerCidVo.class, name = “AnswerCid”),
@JsonSubTypes.Type(value = Terms4IsRightVo.class, name = “IsRight”), })
public interface ITerms extends Comparable<ITerms>, Serializable {
… …
}
示例2
// 指定一个默认子类
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,include = JsonTypeInfo.As.PROPERTY,property = "@Clazz",defaultImpl = Terms4IsRightVo.class)