我的控制器中有此方法:
@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
等)? 最佳答案
解决方案1-动态注册子类型
您可以动态定义子类型。
1.在界面上,定义要用作标识符的JSON字段(@type):
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "@type")
public interface InterfaceClass {
}
2.在您的JSON有效负载中添加“ @type”字段
{
...
"@type": "someName"
}
2.动态注册接口的子类型:
@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) {
}
解决方案2-动态注册自定义反序列化器
如果无法添加(或不希望添加)
@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 {
}