Ich möchte die SerializationConfig.Feature ... -Eigenschaften des von Spring RestTemplate verwendeten Jackson-Mappers aktualisieren. Jede Idee, wie ich darauf zugreifen kann oder wo ich es konfigurieren kann / sollte.
78
Der Standardkonstruktor RestTemplate
registriert eine Reihe von 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());
}
Das MappingJacksonHttpMessageConverter
wiederum erstellt ObjectMapper
Instanz direkt. Sie können diesen Konverter entweder finden und ersetzen ObjectMapper
oder einen neuen registrieren. Das sollte funktionieren:
@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
}
In XML ist es etwas in dieser Richtung:
<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"/>
Beachten Sie, dass der Übergang nicht wirklich 1: 1 ist. Ich muss eine messageConverters
Liste explizit in XML erstellen, während @Configuration
ich mit dem Ansatz auf eine vorhandene Liste verweisen und sie einfach ändern kann. Das sollte aber funktionieren.
RestOperations -> RestTemplate
in@Bean
Definition auf diese Arbeiten machenWenn Sie Spring IOC nicht verwenden, können Sie Folgendes tun (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);
quelle
RestTemplate initialisiert seine Standardnachrichtenkonverter. Sie sollten die
MappingJackson2HttpMessageConverter
durch Ihre eigene Bean ersetzen , die den Objekt-Mapper verwenden sollte, den Sie verwenden möchten. Das hat bei mir funktioniert:@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 }
quelle
myObjectMapper()
aber nicht nurobjectMapper()
. Aus irgendeinem Grund wird die Methode anscheinend nie aufgerufen und Sie erhalten die StandardeinstellungObjectMapper
.restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter);
sollte seinrestTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter());
(beachten Sie die Klammern in MappingJackson2HttpMessageConverter (), was es zu einem Methodenaufruf anstelle einer Referenz macht)mappingJackson2HttpMessageConverter
als Parameter zurrestTemplate
Funktion hinzufügen und es so verwenden, wie es ist.Um die anderen Antworten vervollständigen: wenn Ihr
ObjectMapper
Register nur JacksonModule
mit benutzerdefinierten Serializer / Deserializer, möchten Sie vielleicht Ihr Modul direkt auf das bestehende registrierenObjectMapper
vonRestTemplate
‚s StandardMappingJackson2HttpMessageConverter
wie folgt (Beispiel ohne DI aber das gleiche gilt , wenn DI verwenden):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);
Auf diese Weise können Sie die Konfiguration des Originals
ObjectMapper
(wie von Spring's durchgeführtJackson2ObjectMapperBuilder
) abschließen , anstatt es zu ersetzen.quelle
Mit Spring Boot ist es so einfach wie:
RestTemplate template = new RestTemplateBuilder() .additionalMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper)) .build()
(Getestet mit Spring Boot 2.2.1)
quelle
RestTemplate
haben Sie nur einenMessageConverter
:MappingJackson2HttpMessageConverter
. Aber ich mag es immer nochadditionalMessageConverters
ist nicht wirklich additiv. Es wird ein vollständiger Austausch durchgeführt und Sie verlieren andere Konverter. Es steht auf dem Dokument. (Es wird zur Liste der Konverter des Builders hinzugefügt, die die Instanz vollständig ersetzen.)