Я хочу оновити властивості SerializationConfig.Feature ... властивостей mappers jackson, використовуваних Spring RestTemplate, будь-яка ідея, як я можу до нього дістатися або де я можу / повинен це налаштувати.
Я хочу оновити властивості SerializationConfig.Feature ... властивостей mappers jackson, використовуваних Spring RestTemplate, будь-яка ідея, як я можу до нього дістатися або де я можу / повинен це налаштувати.
Відповіді:
Конструктор за замовчуванням RestTemplate
реєструє набір HttpMessageConverter
s:
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter());
this.messageConverters.add(new SourceHttpMessageConverter());
this.messageConverters.add(new XmlAwareFormHttpMessageConverter());
if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jacksonPresent) {
this.messageConverters.add(new MappingJacksonHttpMessageConverter());
}
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
По MappingJacksonHttpMessageConverter
черзі створює ObjectMapper
екземпляр безпосередньо. Ви можете або знайти цей перетворювач, і замінити, ObjectMapper
або зареєструвати новий перед ним. Це має працювати:
@Bean
public RestOperations restOperations() {
RestTemplate rest = new RestTemplate();
//this is crucial!
rest.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
return rest;
}
@Bean
public MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter() {
MappingJacksonHttpMessageConverter converter = new MappingJacksonHttpMessageConverter();
converter.setObjectMapper(myObjectMapper());
return converter;
}
@Bean
public ObjectMapper myObjectMapper() {
//your custom ObjectMapper here
}
У XML це щось подібне:
<bean id="restOperations" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<util:list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="customObjectMapper"/>
</bean>
</util:list>
</property>
</bean>
<bean id="customObjectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>
Зверніть увагу, що перехід насправді не 1: 1 - я повинен чітко створити messageConverters
список у XML, тоді як за допомогою @Configuration
підходу я міг би посилатися на існуючий і просто модифікувати його. Але це має спрацювати.
RestOperations -> RestTemplate
в @Bean
визначенні , щоб зробити це працює
Якщо ви не використовуєте Spring IOC, ви можете зробити щось подібне (Java 8):
ObjectMapper objectMapper = new ObjectMapper();
// configure your ObjectMapper here
RestTemplate restTemplate = new RestTemplate();
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
messageConverter.setPrettyPrint(false);
messageConverter.setObjectMapper(objectMapper);
restTemplate.getMessageConverters().removeIf(m -> m.getClass().getName().equals(MappingJackson2HttpMessageConverter.class.getName()));
restTemplate.getMessageConverters().add(messageConverter);
RestTemplate ініціалізує свої перетворювачі повідомлень за замовчуванням. Вам слід замінити MappingJackson2HttpMessageConverter
свій власний компонент, який повинен використовувати маппер об'єкта, який ви хочете використовувати. Це працювало для мене:
@Bean
public RestTemplate restTemplate() {
final RestTemplate restTemplate = new RestTemplate();
//find and replace Jackson message converter with our own
for (int i = 0; i < restTemplate.getMessageConverters().size(); i++) {
final HttpMessageConverter<?> httpMessageConverter = restTemplate.getMessageConverters().get(i);
if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter){
restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter());
}
}
return restTemplate;
}
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(myObjectMapper());
return converter;
}
@Bean
public ObjectMapper myObjectMapper() {
// return your own object mapper
}
myObjectMapper()
але не просто objectMapper()
. З якихось причин здається, що метод ніколи не викликається, і ви отримуєте за замовчуванням ObjectMapper
.
restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter);
має бути restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter());
(зверніть увагу на дужки в mappingJackson2HttpMessageConverter (), зробивши це викликом методу замість посилання)
mappingJackson2HttpMessageConverter
як параметр до restTemplate
функції, використовуйте його як є.
Для того, щоб заповнити інші відповіді: якщо ваші ObjectMapper
просто реєструє Джексон Module
до призначених для користувача серіалізатор / deserializers, ви можете зареєструвати ваш модуль безпосередньо на існуючому ObjectMapper
з RestTemplate
«s по замовчуванням MappingJackson2HttpMessageConverter
наступним чином (приклад без DI , але те ж саме при використанні DI):
SimpleModule module = new SimpleModule();
module.addSerializer(...);
module.addDeserializer(...);
MappingJackson2HttpMessageConverter messageConverter = restTemplate.getMessageConverters().stream()
.filter(MappingJackson2HttpMessageConverter.class::isInstance)
.map(MappingJackson2HttpMessageConverter.class::cast)
.findFirst().orElseThrow( () -> new RuntimeException("MappingJackson2HttpMessageConverter not found"));
messageConverter.getObjectMapper().registerModule(module);
Це дозволить вам завершити конфігурацію оригіналу ObjectMapper
(як це зробив Spring's Jackson2ObjectMapperBuilder
), замість того, щоб замінювати його.
Використовуючи Spring Boot, це так просто, як:
RestTemplate template = new RestTemplateBuilder()
.additionalMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
.build()
(Випробувано Spring Boot 2.2.1)
RestTemplate
матиме тільки одне MessageConverter
: MappingJackson2HttpMessageConverter
. Але мені все одно подобається
additionalMessageConverters
насправді не є добавкою. Він виконає повну заміну, і ви втратите інші перетворювачі. Це зазначено в його документі. (Це додає до списку конвертерів розробника, який повністю замінить екземпляри)