Spring HTTP Message Converters Customizing

It’s easy to expose a REST endpoint with Spring:

@RestController
public class SampleController {
@GetMapping(path = "/data", produces = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
public SampleData sampleData() {
return new SampleData(new String[]{"sample1", "sample2"});
}
}

Internally Spring converts the SampleData object using a HttpMessageConverter.

Spring brings a set of default converters and you can customize your own one. For instance, when the SampleData looks like:

@Data
@AllArgsConstructor
public class SampleData {
private String[] data;
}

…the default XML conversion ends up with a following structure:

<SampleData>
<data>
<data>sample1</data>
<data>sample2</data>
</data>
</SampleData>

But you may prefer a different structure:

<SampleData>
<data>sample1</data>
<data>sample2</data>
</SampleData>
Image for post
Image for post
Krucemburk (cut) by Jan Zrzavý

To achieve this with Spring Boot (you need spring-boot-starter-web dependency and @EnableAutoConfiguration annotation on your application configuration), you have just to register a converter bean:

@Bean
public MappingJackson2XmlHttpMessageConverter
mappingJackson2XmlHttpMessageConverter() {
return new MappingJackson2XmlHttpMessageConverter(
new Jackson2ObjectMapperBuilder()
.defaultUseWrapper(false)
.createXmlMapper(true)
.build()
);
}

We could end here as things are so easy with Spring Boot — the converter is registered and used in the needed order automatically.

As a note it is worth to mention another option to customize message converters with Spring Boot — a WebMvcConfigurer configuration. The interface comes actually from Spring MVC, but its usage from within a Spring Boot application has some specifics:

@Configuration
class Config implements WebMvcConfigurer {
@Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
converters.add(0, new MappingJackson2XmlHttpMessageConverter(
new Jackson2ObjectMapperBuilder()
.defaultUseWrapper(false)
.createXmlMapper(true)
.build()
));
}
}

Spring Boot web auto-configuration (concretely WebMvcAutoConfiguration) brings a default configurer which means we can register as many custom configurers we want to without danger to overwrite the default configuration. That's why we can overwrite the configureMessageConvertersmethod without losing the default message converters, but we have to put it at the beginning of the list to take over from the already included defaults (by converting the fist applicable converter will be used).

The Life without Spring Boot

If we have to stick with Spring framework only, to register a converter bean is just no more enough.

One option is to use your own WebMvcConfigurer as we already seen above. But the situation without Spring Boot is slightly different.

Spring Web MVC default web configuration (enabled by annotating a configuration with @EnableWebMvc) collects instances of WebMvcConfigurer into a composite where all the converters live in a common list. This means, overwriting the configureMessageConvertersmethod would remove the default converters which is, usually, undesirable. Here, the method will do the job (again, you have to put the custom converter at the beginning of the list):

@EnableWebMvc
@Configuration
class MessageConvertersConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(
List<HttpMessageConverter<?>> converters) {
converters.add(0, new MappingJackson2XmlHttpMessageConverter(
new Jackson2ObjectMapperBuilder()
.defaultUseWrapper(false)
.createXmlMapper(true)
.build()
));
}
}

Another options is to overwrite the entire configuration (assumes removing @EnableWebMvc from your codebase). This is very similar to the previous solution:

@Configuration
class WebConfig extends WebMvcConfigurationSupport {
@Override
protected void extendMessageConverters(
List<HttpMessageConverter<?>> converters) {
converters.add(0, new MappingJackson2XmlHttpMessageConverter(
new Jackson2ObjectMapperBuilder()
.defaultUseWrapper(false)
.createXmlMapper(true)
.build()
));
}
}

As you can see, there is more to be aware of when working without convenience of using Spring Boot, but it’s still pretty straightforward.

And that’s it. I hope this helped a bit and wish you happy message converting!

You can find working examples on my Github:

Originally published on my blog.

Written by

Software developer and occasional blogger: https://blog.ttulka.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store