WebFlux:如何反序列化控制器的接口参数?

WebFlux: how to deserialize interface parameter of a Controller?

我正在使用 Spring Webflux,我需要反序列化作为 Restcontroller.

参数传递的接口对象

请注意,我不能以任何方式编辑界面,因为它来自另一个库。我在这里使用 Lombok 来减少样板代码。

这是界面

public interface MyInterface {
    String getField();
    void setField(String field);
}

有相应的实现

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyInterfaceImpl implements MyInterface {
    private String field;
}

和 Rest 控制器

@RestController
public class TestController {
    @PostMapping("/interface/test")
    public String test(@RequestBody MyInterface myInterface){
        return myInterface.toString();
    }
}

在这个例子中,我使用了 MyInterface 的 JSON:

{
    "field":"Test interface field"
}

现在,如果我尝试像上面那样调用端点 JSON, 我收到以下错误:

org.springframework.core.codec.CodecException: Type definition error: [simple type, class project.dto.model.MyInterface]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `project.dto.model.MyInterface` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 1]

我所做的是实现一个自定义 JsonDeserializer

public class MyInterfaceDeserializer extends JsonDeserializer<MyInterface> {
    @Override
    public MyInterface deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        return jsonParser.readValueAs(MyInterfaceImpl.class);
    }
}

并将其作为 模块提供:

@Configuration
public class Jacksonconfiguration {

    @Bean
    Module myInterfaceDeserializerModule(){
        SimpleModule module = new SimpleModule();
        module.addDeserializer(MyInterface.class, new MyInterfaceDeserializer());
        return module;
    }
}

然而,模块似乎没有按照记录自动注册,反序列化错误仍然存​​在。 如何使 MyInterface 自动从控制器参数反序列化?

如果你有预配置的objectMapper,你可以使用CommandLineRunner添加模块:

@Configuration
public class JacksonConfiguration implements CommandLineRunner {
    
    private final ObjectMapper objectMapper;
    
    public JacksonConfiguration(final ObjectMapper objectMapper ) {
            this.objectMapper = objectMapper;
    }
    
    @Override
    public void run(final String... args ) {
        SimpleModule module = new SimpleModule();
        module.addDeserializer( MyInterface.class, new MyInterfaceDeserializer() );
        objectMapper.registerModule( module );
    }
}