克服“不能构造interfaceclass的示例”而不提示父对象

u1ehiz5o  于 2021-07-09  发布在  Java
关注(0)|答案(1)|浏览(185)

我的控制器中有以下方法:

@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 . 然后延伸 AbstractClassClassImpl . 错误只会变成:

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

一如预期。
我真的很期待springboot处理组件发现,因为只有一个具体的实现 InterfaceClass 或者 AbstractClass ,即 ClassImpl 在我的课堂上。也许我做错了什么?我怎样才能克服这一点,而不明确暗示 InterfaceClass 在何处实施(例如:否 @JsonDeserialize 等等)?

8dtrkrch

8dtrkrch1#

解决方案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.在具体类中指定“@type”名称(可选):

//Optional, otherwise uses the Simple class name (ie: 'ClassImpl')
@JsonTypeName("someName") 
public class ClassImpl implements InterfaceClass {
}

5.use现在可以使用带有@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 {
}

相关问题