Return xml from spring REST webservice

Returning JSON from a REST services is set up by default within Spring Boot. We will look at how to set up Spring Boot to return XML as the response.

Detailed Video Notes

In episode 10 we walked through building a basic RESTFul Service with spring boot. Spring boot by default should render a JSON response as long as Jackson2 is configured on the classpath. In this episode we will show how to configure Spring boot to return xml from a URL while using a @RestController.

We cloned our repo in episode 10 so lets take a quick minute to review what we set up. We set up this project using a spring starter and created an AgencyController that returned a AgencyResource object. If we start our server and make a request to localhost:8080/agencies we should see a JSON output of an agency object and mocked up data.

What is WebMvcConfigurerAdapter?

[0:42]

Since we are using java based configuration we need to be able to modify the default spring configuration. To do this we will extend WebMvcConfigurerAdapter. WebMvcConfigurerAdapter is a class with empty method implementations of WebMvcConfigurer that acts as a callback class. When spring fires up it looks for any classes of this type and calls the implementation methods which allows us to modify the configuration.

The method that we will want to override is configureMessageConverters which will allow us to configure a HttpMessageConverters to support rendering xml.

@Override
public void configureMessageConverters(List<HttpMessageConverter < ? >> converters) {
}

Adding XStream to classpath

[1:18]

There are various libraries for handling marshalling and unmarshalling of xml to and from java such as Castor, XStream and Jackson. For this demonstration lets use XStream so we will need to add it our class path. XStream is touted as a simple and easy library to serialize objects to XML and back again.

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.7</version>
</dependency>

Specifying a MarshallingHttpMessageConverter

[1:38]

If you recall a @RestController is a special annotation that combines @Controller and a @ResponseBody. A @ResponseBody tells Spring MVC that it does not need to look for a view and it should be returned directly to the response. When it sends the object to the response it looks for an associated HttpMessageConverter for the type of request made. In our prior example when you make a request to localhost:8080/agencies it uses MappingJackson2HttpMessageConverter so we need to define a message converter to handle xml.

We will override the configureMessageConverters method and supply a MarshallingHttpMessageConverter setting the the MediaType or MIME type of XML and supplying a XStreamMarshaller from the xstream library as the marshaller and unmarshaller.

@Override
public void configureMessageConverters(List<HttpMessageConverter< ?>> converters) {

    List<MediaType> mediaType = new ArrayList<>();
    mediaType.add(MediaType.TEXT_XML);

    MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
    xmlConverter.setSupportedMediaTypes(mediaType);

    XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
    xmlConverter.setMarshaller(xstreamMarshaller);
    xmlConverter.setUnmarshaller(xstreamMarshaller);

    converters.add(xmlConverter);
}

Making a request with Accept Header

[2:29]

Using a chrome plugin Advanced Rest Client we will make a request to localhost:8080/agencies while specifying the Accept header to be text/xml.

<?xml version="1.0" encoding="UTF-8"?>
<list>
   <demo.AgencyResource>
      <id>1</id>
      <name>all state</name>
      <EIN>123</EIN>
   </demo.AgencyResource>
   <demo.AgencyResource>
      <id>2</id>
      <name>fcci insurance group</name>
      <EIN>456</EIN>
   </demo.AgencyResource>
   <demo.AgencyResource>
      <id>3</id>
      <name>farmers</name>
      <EIN>789</EIN>
   </demo.AgencyResource>
   <demo.AgencyResource>
      <id>4</id>
      <name>met life</name>
      <EIN>167</EIN>
   </demo.AgencyResource>
</list>

Content negotiation using path extension

[3:0]

As you seen above you need to specify the Accept header. This approach is less common and if you are developing an API a more convenient way for developers/programmers and consumers is to specify the path extension. So in our case .xml or .json at the end of your request. To do this there is a small configuration to give a hint to ContentNegotiatingViewResolver class.

Again we will override a WebMvcConfigurerAdapter method named configureContentNegotiation we will do three things. First we will set the default content type to MediaType.APPLICATION_JSON which will route request without a path extension to json. Second we will tell ContentNegotiationConfigurer to favor path extension over parameter or accept headers. Last we will register xml to the assoicated mime type. Now navigating to localhost:8080/agencies.xml in a browser we will see xml returned.

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.defaultContentType(MediaType.APPLICATION_JSON);
    configurer.favorPathExtension(true);
    configurer.mediaType("xml", MediaType.TEXT_XML);
}

Hope you enjoyed today's level up lunch, have a great day!