Я использую Spring Webflux, и мне нужно десериализовать объект интерфейса, переданный в качестве параметра Restcontroller
.
Обратите внимание, что мне не разрешено каким-либо образом редактировать интерфейс, так как он из другой библиотеки. Я использую Lombok здесь, чтобы сократить шаблонный код.
это интерфейс
public interface MyInterface {
String getField();
void setField(String field);
}
с соответствующей реализацией
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyInterfaceImpl implements MyInterface {
private String field;
}
и контроллер отдыха
@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 автоматически десериализоваться из параметра контроллера?
Если у вас есть предварительно настроенный 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 );
}
}