Я использую spring-boot с spring-web и jackson.
Проблема: когда RestTemplate автоматически инициализируется Spring, конструктор получает дубликат MessageConverters:
org.springframework.http.converter.ByteArrayHttpMessageConverter@6a1b4854,
org.springframework.http.converter.StringHttpMessageConverter@2d5b549b,
org.springframework.http.converter.StringHttpMessageConverter@6a175162,
org.springframework.http.converter.ResourceHttpMessageConverter@7641c4e7,
org.springframework.http.converter.ResourceRegionHttpMessageConverter@650a0b50,
org.springframework.http.converter.xml.SourceHttpMessageConverter@55e3b64d,
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@52f71d2,
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@f3c27e9,
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@7d31fb6c,
org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter@701c413,
org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter@48543f11
Видите ли, есть 3 дубликата:
StringHttpMessageConverter
MappingJackson2HttpMessageConverter
MappingJackson2XmlHttpMessageConverter
Поскольку я сам не инициализирую преобразователи сообщений: почему контекст приложения вообще содержит повторяющиеся преобразователи, которые затем добавляются в шаблон resttemplate?
Особенно: не сбивает ли это с толку (де) сериализацию, если некоторые конвертеры повторяются (но с другой конфигурацией)?
Например: ObjectMapper первого MappingJackson2HttpMessageConverter содержит больше registeredModuleTypes[Jdk8Module, JavaTimeModule, ParamterNamesModule, JsonComponentModule, GeoModule], чем 2-й (который содержит только: [Jdk8Module, JavaTimeModule]).
Имеет ли это смысл?
Он создается через RestTemplateAutoConfiguration.restTemplateBuilder(), там уже есть все дубликаты MessageConverters.
Это происходит от RestTemplateAutoConfiguration.restTemplateBuilder(). Таким образом, он просто вводит любой HttpMessageConverters, найденный в пути к классам. Вопрос в том, почему могут быть дубликаты?
Ну вот и все, что мне удалось получить.
Добавлено объяснение того, как Spring выбирает HttpMessageConverter. См. внизу.




Виновник здесь, в HttpMessageConverters
public HttpMessageConverters(boolean addDefaultConverters,
Collection<HttpMessageConverter<?>> converters) {
List<HttpMessageConverter<?>> combined = getCombinedConverters(converters,
addDefaultConverters ? getDefaultConverters() : Collections.emptyList());
combined = postProcessConverters(combined);
this.converters = Collections.unmodifiableList(combined);
}
В частности, эта строка (отформатированная)
List<HttpMessageConverter<?>> combined =
getCombinedConverters(
converters,
addDefaultConverters
? getDefaultConverters()
: Collections.emptyList());
Коллекция converters содержит отсканированные HttpMessageConverter(и).
На основе среды.
Затем этот список объединяется со списком По умолчанию, предоставленным WebMvcConfigurationSupport.
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
private static final boolean romePresent;
private static final boolean jaxb2Present;
private static final boolean jackson2Present;
private static final boolean jackson2XmlPresent;
private static final boolean jackson2SmilePresent;
private static final boolean jackson2CborPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
...
Фактическая документация для WebMvcConfigurationSupport состояний
This class registers ... ... a range of
HttpMessageConvertersdepending on the third-party libraries available on the classpath.
Отсканированные HttpMessageConverter(s) находятся и создаются через HttpMessageConvertersAutoConfiguration, документация которого находится
Auto-configuration for
HttpMessageConverters.
Этот класс сам по себе предоставляет StringHttpMessageConverter
@Bean
@ConditionalOnMissingBean
public StringHttpMessageConverter stringHttpMessageConverter() {
StringHttpMessageConverter converter = new StringHttpMessageConverter(
this.properties.getCharset());
converter.setWriteAcceptCharset(false);
return converter;
}
Затем он импортирует автоконфигурации Джексона или Гсона.
@Import({
JacksonHttpMessageConvertersConfiguration.class
GsonHttpMessageConvertersConfiguration.class,
JsonbHttpMessageConvertersConfiguration.class
})
И вот как эти основанные на среде «суммируются» с предопределенными.
Spring не путается с дубликатами, потому что он просто берет первый совместимый.
Посмотрите, как выбирается HttpMessageConverter
Вы можете видеть, что это всего лишь простой цикл for, и каждого новообращенного просят сказать: «Могу ли я сделать это?» методом canWrite
Выбирается первый действительный.
tyvm за подробное понимание!
@membersound, нет проблем. Это было весело. Если вам нужны другие разъяснения, дайте мне знать.
Не могли бы вы установить точку останова в конструкторе и опубликовать весь стек вызовов? Я хочу увидеть, откуда он создается.