Мне нужно переопределить зависимость ObjectMapper по умолчанию (и ее конфигурации по умолчанию) MappingJackson2HttpMessageConverter при использовании класса RestClient Springboot.
Не каждый сторонний API, с которым я взаимодействую, соответствует конфигурации по умолчанию, которую, похоже, навязывает Springboot.
Мне удалось успешно переопределить значение по умолчанию ObjectMapper с помощью следующего кода, но:
Мне интересно, есть ли лучший и более очевидный способ добиться этого.
Мне кажется странным, что изменить значение по умолчанию ObjectMapper, используемое RestClient, так сложно.
private final ObjectMapper objectMapper;
public RestClientConfig(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Bean("torii")
public RestClient toriiApi() {
return RestClient.builder()
.messageConverters(this::initMessageConverters)
.baseUrl(toriiApiHost)
.defaultHeader("Authorization", generateBasicAuthHeaderValue(torriApiBasicAuthUser, torriApiBasicAuthPassword))
.defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE)
.defaultHeader("Accepted", MediaType.APPLICATION_JSON_VALUE)
.build();
}
private void initMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
AtomicInteger counter = new AtomicInteger();
AtomicReference<Integer> jacksonConvertIndex = new AtomicReference<>();
messageConverters.forEach(httpMessageConverter -> {
if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) {
jacksonConvertIndex.set(counter.get());
}
counter.getAndIncrement();
});
messageConverters.remove(jacksonConvertIndex.get().intValue());
messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
}
Ты прав. ObjectMapper, передаваемый в toriiApi(), не использовался. Я передаю правильно настроенный objectMapper, который хочу использовать, через конструктор (и добавил этот код в свой вопрос).




Вы можете просто установить objectMapper на существующий MappingJackson2HttpMessageConverter, поскольку у него есть публичный сеттер, унаследованный от AbstractJackson2HttpMessageConverter:
private void initMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
messageConverters.forEach(httpMessageConverter -> {
if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter jacksonConverter) {
jacksonConverter.setObjectMapper(objectMapper);
}
});
}
Помимо этой настройки, я думаю, что это подходящее использование API в вашей ситуации, и я предполагаю, что вы хотите сохранить все конвертеры сообщений по умолчанию и изменить только MappingJackson2HttpMessageConverter - параметр на RestClient.Builder#messageConverters называется configurer, так что кажется, что это ожидается, что список будет изменен. В официальной документации также рекомендуется использовать метод messageConverters:
По умолчанию RestClient и RestTemplate регистрируют все встроенные преобразователи сообщений, в зависимости от доступности базовых библиотек в пути к классам. Вы также можете настроить использование преобразователей сообщений явно, используя метод messageConverters() в компоновщике RestClient или через свойство messageConverters объекта RestTemplate.
И это особенно советует в отношении MappingJackson2HttpMessageConverter:
Если вам нужен дополнительный контроль (в случаях, когда для определенных типов необходимо предоставить собственные сериализаторы/десериализаторы JSON), вы можете внедрить собственный ObjectMapper через свойство ObjectMapper.
Возможно, вы предпочтете использовать перегрузку RestClient.builder(RestTemplate) и вместо этого установить messageConverters в RestTemplate, но если вы хотите сохранить функциональность использования слегка измененного списка по умолчанию, вам придется делать то же самое с messageConverters в RestTemplate. Если вас не волнует сохранение остальных MessageConverters, вы можете использовать RestTemplate с нужным вам единственным MappingJackson2HttpMessageConverter.
Спасибо. Установка правильно настроенного ObjectMapper на существующий конвертер работает на 100% и проще, чем мой первоначальный подход.
В вашем фрагменте вы передаете
ObjectMapperвtoriiApi(), чтобы не использовать его, а затем вinitMessageConverters()используется необъявленная переменнаяobjectMapper... Непонятно, что вы пытались.