#jackson #spring-webflux
#джексон #spring-webflux
Вопрос:
Я использую Spring Webflux, и мне нужно десериализовать объект интерфейса, переданный в качестве параметра a 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();
}
}
В этом примере я использую этот JSON для MyInterface:
{
"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 автоматически десериализовался из параметра контроллера?
Ответ №1:
Если у вас есть предварительно настроенный 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 );
}
}