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 );
}
}
我正在使用 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 );
}
}