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.
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.
Antworten:
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 machen
Wenn 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);
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
}
myObjectMapper()
aber nicht nur objectMapper()
. Aus irgendeinem Grund wird die Methode anscheinend nie aufgerufen und Sie erhalten die Standardeinstellung ObjectMapper
.
restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter);
sollte sein restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter());
(beachten Sie die Klammern in MappingJackson2HttpMessageConverter (), was es zu einem Methodenaufruf anstelle einer Referenz macht)
mappingJackson2HttpMessageConverter
als Parameter zur restTemplate
Funktion hinzufügen und es so verwenden, wie es ist.
Um die anderen Antworten vervollständigen: wenn Ihr ObjectMapper
Register nur Jackson Module
mit benutzerdefinierten Serializer / Deserializer, möchten Sie vielleicht Ihr Modul direkt auf das bestehende registrieren ObjectMapper
von RestTemplate
‚s Standard MappingJackson2HttpMessageConverter
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ührt Jackson2ObjectMapperBuilder
) abschließen , anstatt es zu ersetzen.
Mit Spring Boot ist es so einfach wie:
RestTemplate template = new RestTemplateBuilder()
.additionalMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
.build()
(Getestet mit Spring Boot 2.2.1)
RestTemplate
haben Sie nur einen MessageConverter
: MappingJackson2HttpMessageConverter
. Aber ich mag es immer noch
additionalMessageConverters
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.)