我的控制器中有这个方法:
@RequestMapping(method = RequestMethod.POST)
InterfaceClass insert(@RequestBody InterfaceClass interfaceClass) {
// Do something
}
我得到的错误非常直接且不言自明:
Can not construct instance of InterfaceClass: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information.
基本上,我需要告诉Spring我有InterfaceClass
,ClassImpl
的具体实现。
我试过了:
@JsonRootName("InterfaceClass")
public class ClassImpl implements InterfaceClass {
}
到任何程度。我无法使用@JsonTypeInfo
,因为父接口类InterfaceClass
不应该知道ClassImpl
并且它们位于不同的模块。我也尝试过:
使用摘要InterfaceClass
实施AbstractClass
并输入:
@JsonDeserialize(as = AbstractClass.class)
位于InterfaceClass
之上。然后使用AbstractClass
扩展ClassImpl
。错误只会变成:
Can not construct instance of InterfaceClass: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information.
进一步尝试:
public class ControllerClass<E extends InterfaceClass> {
@RequestMapping(method = RequestMethod.POST)
InterfaceClass insert(@RequestBody E interfaceClass) {
InterfaceClass object = (InterfaceClass) interfaceClass;
}
}
,结果是:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to InterfaceClass
正如所料。
我真的希望Spring Boot能够处理组件发现,因为InterfaceClass
或AbstractClass
只有一个具体实现,在我的类路径中是ClassImpl
。也许我做错了什么?我怎样才能克服这个问题,而没有明确暗示InterfaceClass
实现的位置(例如没有@JsonDeserialize
等)?
答案 0 :(得分:3)
您可以动态定义子类型。
<强> 1。在界面上,定义要用作标识符的JSON字段(@type):
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "@type")
public interface InterfaceClass {
}
<强> 2。将“@type”字段添加到您的JSON有效负载
{
...
"@type": "someName"
}
<强> 2。动态注册inteface的子类型:
@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() {
public void configure(ObjectMapper objectMapper) {
objectMapper.registerSubtypes(ClassImpl.class);
super.configure(objectMapper);
};
};
return builder;
}
<强> 4。在具体类上指定“@type”名称(可选):
//Optional, otherwise uses the Simple class name (ie: 'ClassImpl')
@JsonTypeName("someName")
public class ClassImpl implements InterfaceClass {
}
<强> 5。现在可以使用@RequestBody的界面:
@RequestMapping(method = RequestMethod.POST)
InterfaceClass insert(@RequestBody InterfaceClass interfaceClass) {
}
如果无法(或不想要)添加@type
字段,您还可以为您的界面定义自定义反序列化器,实际上会创建ClassImpl
:
<强> 1。定义自定义反序列化器:
class ClassImplJsonDeserializer extends JsonDeserializer<ClassImpl> {
@Override
public ClassImpl deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return jp.readValuesAs(ClassImpl.class).next();
}
}
<强> 2。动态设置自定义反序列化器:
@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.deserializerByType(InterfaceClass.class, new ClassImplJsonDeserializer());
return builder;
}
第3。从界面中删除@JsonTypeInfo:
public interface InterfaceClass {
}