我的控制器中有此方法:

@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我有InterfaceClassClassImpl的具体实现。

我试过了:

@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能够处理组件发现,因为在我的类路径中只有InterfaceClassAbstractClass的一个具体实现,即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 {
}

10-04 10:26