Как написать пользовательский преобразователь для получения данных с аннотацией @RequestBody

#spring-boot #rest #java-11

Вопрос:

Я пытаюсь написать пользовательский конвертер для получения данных, отправленных в приложение REST. Объект, который я хочу заполнить, уже имеет свой собственный конструктор, который принимает строку JSON, поэтому я должен использовать ее вместо десериализатора Джексона, который обычно использует Spring.

Я пробовал несколько разных вещей, но я продолжаю получать следующее исключение:

 org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class xxx.yyy.zzz.MyType]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `xxx.yyy.zzz.MyType` (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: (PushbackInputStream); line: 1, column: 1]
        at         at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:281) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:250) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
 

Мой преобразователь выглядит так:

 public class MyConverter extends AbstractHttpMessageConverter<MyType> {
    public MyConverter() {
        super(/*MediaType.TEXT_PLAIN*/ MediaType.APPLICATION_JSON);
    }

    @Override
    protected boolean supports(Class<?> type) {
        return MyType.class.isAssignableFrom(type);
    }

    @Override
    protected MyType readInternal(Class<? extends MyType> type, HttpInputMessage inputMessage) throws IOException {
        String str = ..... read data from inputMessage

        return MyType.build(str);
    }

    @Override
    protected void writeInternal(MyType s, HttpOutputMessage outputMessage) {
    }
}

 

а контроллер-это:

 @RequestMapping(method = RequestMethod.POST)
public void add(@RequestBody MyType data) {
    System.out.println("add:"   data.toString());
}
 

Даже если изменить тип среды в конструкторе для MyConverter на «Тип среды».ВСЕ это все равно провалится. Любопытно, что если я изменю его на TEXT_PLAIN и опубликую с типом содержимого «текст/обычный», это сработает!

Ответ №1:

Отвечая на мой собственный вопрос. Проблема оказалась в порядке обработки объектов HttpMessageConverter. Встроенные преобразователи обрабатывались и выходили из строя, прежде чем у моего преобразователя появился шанс.

Это не лучший код, но он работает:

 @Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void extendMessageConverters(@Nonnull List<HttpMessageConverter<?>> converters) {
        List<HttpMessageConverter<?>> temp = new ArrayList<>();
        temp.add(new MyConverter());
        temp.addAll(converters);

        converters.clear();
        converters.addAll(temp);
    }
}
 

Я не могу до конца поверить, что это лучший ответ на то, что, я думаю, должно быть довольно стандартной проблемой. Если кто-нибудь может предложить лучший ответ, я с радостью приму это вместо этого