What is the most convenient way to influence the priority of the message converters Spring applies when POSTing with RestTemplate
?
Use case: I want to ensure a given entity is POSTed as JSON rather than e.g. XML when I do restTemplate.postForEntity(url, entity, Void.class)
.
Default
By default the entity is converted to XML because the MappingJackson2XmlHttpMessageConverter
takes precedence over the MappingJackson2HttpMessageConverter
. The default list of converters for my app appears to be (Spring scans the classpath to see what's available):
Option 1
You can configure the message converters explicitly for a given RestTemplate
instance like so restTemplate.setMessageConverters(Lists.newArrayList(new MappingJackson2HttpMessageConverter()))
. This is inconvenient if the instance is shared (as a Spring bean for example) as you might need converter X in one case and converter Y in a different one.
Option 2
You can set Accept
and Content-Type
HTTP headers explicitly in which case Spring will use a matching message converter. The downside is that you have to resort to RestTemplate.exchange
instead of RestTemplate.postForEntity
which means: extra code, less convenience.
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity requestEntity = new HttpEntity(entity, requestHeaders);
restTemplate.exchange(url, HttpMethod.POST, requestEntity, Void.class);
Option 3
This might be what I'm looking for :)
This issue is answered in detail here.
Basically, when you add the below-mentioned library, it adds MappingJackson2XmlHttpMessageConverter
before MappingJackson2HttpMessageConverter
. As a result, Spring boot assumes every request accepts application/XML
.
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
To avoid this behaviour, you might want to swap the two message converters.
Example:
@Bean
RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// move XML converter to the end of list
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (int i = 0; i < messageConverters.size() -1 ; i++) {
if (messageConverters.get(i) instanceof MappingJackson2XmlHttpMessageConverter) {
Collections.swap(messageConverters, i,messageConverters.size() - 1);
}
}
restTemplate.setMessageConverters(messageConverters);
// add interceptors if necessary
restTemplate.setInterceptors(Collections.singletonList(catalogInterceptior()));
return restTemplate;
}
According to the Spring javadoc (https://docs.spring.io/spring-framework/docs/current/javadoc-api/index.html?org/springframework/web/client/RestTemplate.html) you can still use postForEntity,
public <T> ResponseEntity<T> postForEntity(java.lang.String url,
@Nullable
java.lang.Object request,
java.lang.Class<T> responseType,
java.util.Map<java.lang.String,?> uriVariables)
throws RestClientException
....
The request
parameter can be a HttpEntity
in order to add additional HTTP headers to the request.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With