Java 使用@JsonTypeInfo和@JsonSubTypes,反序列化没有基类和类型信息的具体子类的对象
使用Java 使用@JsonTypeInfo和@JsonSubTypes,反序列化没有基类和类型信息的具体子类的对象,java,spring-boot,rest,jackson,polymorphism,Java,Spring Boot,Rest,Jackson,Polymorphism,使用@JsonTypeInfo和@JsonSubTypes,可以反序列化没有类型信息的具体子类的对象吗 假设我有一个抽象的Animal类: import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 导入com.fasterxml.jackson.annotation.JsonSubTypes; 导入com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonIgnorePropertie
@JsonTypeInfo
和@JsonSubTypes
,可以反序列化没有类型信息的具体子类的对象吗
假设我有一个抽象的Animal
类:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
导入com.fasterxml.jackson.annotation.JsonSubTypes;
导入com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonIgnoreProperties(ignoreUnknown=true)
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME,include=JsonTypeInfo.As.PROPERTY,PROPERTY=“type”)
@JsonSubTypes({
@JsonSubTypes.Type(value=Dog.class,name=“Dog”),
@JsonSubTypes.Type(value=Cat.class,name=“Cat”)
})
公共抽象类动物{
私有字符串名称;
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
}
和狗子类:
公共类狗扩展了动物{
私家犬;
公犬(){
}
公犬(犬种名称、犬种){
集合名(名称);
芦苇(品种);
}
公共字符串getbride(){
回归品种;
}
公共芦苇(弦品种){
这个品种;
}
}
我知道我可以根据父类实例化子类对象,如下所示:
ObjectMapper objectMapper = new ObjectMapper()
.addHandler(new DeserializationProblemHandler() {
@Override
public JavaType handleMissingTypeId(DeserializationContext ctxt,
JavaType baseType,
TypeIdResolver idResolver,
String failureMsg)
throws IOException {
return baseType;
}
});
{
“类型”:“狗”,
“姓名”:“杰克”,
“品种”:“牧羊人”
}
Animal反序列化ddog=objectMapper.readValue(dogJson,Animal.class);
但是,有时我想直接实例化子类对象,而不使用父类:
{
“姓名”:“杰克”,
“品种”:“牧羊人”
}
Dog反序列化ddog=objectMapper.readValue(dogJson,Dog.class);
子类对象将被发送到端点:
@PostMapping(/endpoint)
公共响应发送数据到JMS(
@RequestBody狗请求,@RequestHeader映射头)引发异常{
//...
}
有可能吗?您只需要像这样创建ObjectMapper
:
ObjectMapper objectMapper = new ObjectMapper()
.addHandler(new DeserializationProblemHandler() {
@Override
public JavaType handleMissingTypeId(DeserializationContext ctxt,
JavaType baseType,
TypeIdResolver idResolver,
String failureMsg)
throws IOException {
return baseType;
}
});
我找到了解决办法
您需要启用MapperFeature。使用\u BASE\u TYPE\u作为\u DEFAULT\u IMPL
以使用具体的子类直接反序列化对象,而不使用类型信息
根据官方文件,
MapperFeature.使用\u BASE\u TYPE\u作为\u DEFAULT\u IMPL
是
指定多态值的声明基类型是否为
如果没有显式的默认类,则用作“默认”实现
通过@JsonTypeInfo.defaultImpl
注释指定
接下来,您需要定制将JSON请求转换为Java对象的MappingJackson2HttpMessageConverter
,如下所示
@Bean
公共映射Jackson2HttpMessageConverter映射Jackson2HttpMessageConverter(){
MappingJackson2HttpMessageConverter jsonConverter=新的MappingJackson2HttpMessageConverter();
ObjectMapper ObjectMapper=新的ObjectMapper();
objectMapper.enable(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL);
setObjectMapper(objectMapper);
返回jsonConverter;
}
尝试时发生了什么?如果忽略类型
字段:JSON解析错误:在尝试解析…
的子类型时缺少类型id,那么当您显式提供Dog.class
时,您不应该得到它。是的,您是对的。JSON对象在@PostMapping
注释下作为@RequestBody Dog
传递时被反序列化。但是,我确实提供了子类名称,它不会自动使用Dog.class
吗?是否提供了子类名称Where/how?您的问题没有包含足够的详细信息,无法回答。代码做什么?当ObjectMapper没有看到type
字段时,它将尝试DeserializationProblemHandler
来处理缺少的类型id,因此您可以添加一个新的DeserializationProblemHandler
来返回所需的JavaType
,我使用的是jackson 2.9.4,它没有MapperFeature。使用\u BASE\u TYPE\u作为\u DEFAULT\u IMPL