240604-jaskson反序列化为接口(抽象类)时的多态问题

363 阅读2分钟

问题原因

json反序列化为接口(抽象类)时,同时该接口(抽象类)有多个实现(继承)时,jackson不知道反序列化为哪个子类对象。

image.png

报错信息

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)

参考文章

www.cnblogs.com/noah-sheng/…

image.png