在不提示父级的情况下克服"Can not construct instance of InterfaceClass"
Overcome "Can not construct instance of InterfaceClass" without hinting the parent
我的控制器中有这个方法:
@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
作为父接口 class InterfaceClass
不应该知道 ClassImpl
并且它们在不同的模块中 。我也尝试过:
用摘要 AbstractClass
实现 InterfaceClass
并输入:
@JsonDeserialize(as = AbstractClass.class)
在 InterfaceClass
之上。然后用 ClassImpl
扩展 AbstractClass
。错误简单地变成:
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
在我的 class路径。也许我做错了什么?如果不明确提示 InterfaceClass
它的实现位置(例如没有 @JsonDeserialize
等),我该如何克服这个问题?
解决方案 1 - 动态注册子类型
您可以动态定义子类型。
1。在界面上,定义一个JSON字段(@type)作为标识符:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "@type")
public interface InterfaceClass {
}
2。将“@type”字段添加到您的 JSON 有效载荷
{
...
"@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。在具体的 class(可选)上指定“@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 {
}
我的控制器中有这个方法:
@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
作为父接口 class InterfaceClass
不应该知道 ClassImpl
并且它们在不同的模块中 。我也尝试过:
用摘要 AbstractClass
实现 InterfaceClass
并输入:
@JsonDeserialize(as = AbstractClass.class)
在 InterfaceClass
之上。然后用 ClassImpl
扩展 AbstractClass
。错误简单地变成:
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
在我的 class路径。也许我做错了什么?如果不明确提示 InterfaceClass
它的实现位置(例如没有 @JsonDeserialize
等),我该如何克服这个问题?
解决方案 1 - 动态注册子类型
您可以动态定义子类型。
1。在界面上,定义一个JSON字段(@type)作为标识符:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "@type")
public interface InterfaceClass {
}
2。将“@type”字段添加到您的 JSON 有效载荷
{
...
"@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。在具体的 class(可选)上指定“@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 {
}