Spring MVC Content Negotiation XML JSON
This tutorial shows you how to use Spring MVC Content Negotiation XML JSON features. According to wikipedia, “content negotiation is a mechanism defined in the HTTP specification that makes it possible to serve different versions of a document at the same URI, so that user agents/users can specify which version fit their capabilities the best.”
We show you how to negotiate between XML and JSON using HTTP Accept header, via URL file extension, a specific request parameter or fallback on a default content type when nothing of the previous is requested.
Maven Dependency
We use Apache Maven to manage our project dependencies. Add the following dependencies so Maven can automatically manage the dependencies. Make sure the com.fasterxml.jackson.dataformat:jackson-dataformat-xml
resides on the classpath for XML marshalling.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.memorynotfound.spring.mvc</groupId>
<artifactId>xml-view-resolver</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>SPRING-MVC - ${project.artifactId}</name>
<url>https://memorynotfound.com</url>
<packaging>war</packaging>
<properties>
<encoding>UTF-8</encoding>
<spring.version>4.2.6.RELEASE</spring.version>
</properties>
<dependencies>
<!-- spring libraries -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- xml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.7.4</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
Spring MVC Content Negotiation XML JSON – Configuration
When we extend from the WebMvcConfigurerAdapter
we can override some convinient methods for managing the content negotiation manager.
The configureContentNegotiation(ContentNegotiationConfigurer configurer)
method – as the name implies – configures the content negotiation. We can register a default content type that’ll be served if none of the other content negotiation properties are requested.
The configureViewResolvers(ViewResolverRegistry registry)
method registers different view resolvers that the application can serve. In this example we register both the MappingJackson2XmlView
for serving XML and the MappingJackson2JsonView
for serving JSON.
package com.memorynotfound.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import org.springframework.web.servlet.view.xml.MappingJackson2XmlView;
@EnableWebMvc
@Configuration
@ComponentScan("com.memorynotfound")
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.defaultContentType(MediaType.APPLICATION_JSON_UTF8)
.parameterName("type")
.favorParameter(true)
.ignoreUnknownPathExtensions(false)
.ignoreAcceptHeader(false)
.useJaf(true);
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(
new MappingJackson2XmlView(),
new MappingJackson2JsonView());
}
}
Here you can find the equivallent Spring MVC XML Configuration.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.memorynotfound" />
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="defaultContentType" value="APPLICATION_JSON_UTF8"/>
<property name="parameterName" value="type"/>
<property name="favorParameter" value="true"/>
<property name="ignoreUnknownPathExtensions" value="false"/>
<property name="ignoreAcceptHeader" value="false"/>
<property name="useJaf" value="true"/>
</bean>
<mvc:view-resolvers>
<mvc:content-negotiation>
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.xml.MappingJackson2XmlView"/>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</mvc:default-views>
</mvc:content-negotiation>
</mvc:view-resolvers>
</beans>
We need to register the DispatcherServlet
which acts like a front controller for mapping the requests to the correct endpoint. We pass the previous configuration file to the servlet using the getServletConfigClasses()
method.
package com.memorynotfound.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
}
Creating a Rest Endpoint
First, we create a simple POJO which will be returned as a response.
package com.memorynotfound.model;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Course {
private Integer id;
private String name;
private Date date;
public Course() {
}
public Course(Integer id, String name, Date date) {
this.id = id;
this.name = name;
this.date = date;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public Date getDate() {
return date;
}
}
Next, we created a rest endpoint which will return an instance of the previous Course
class. Note that this code has no logic to return a specific view. The view resolution is managed by the content negotiation manager, which we configured earlier.
package com.memorynotfound.controller;
import com.memorynotfound.model.Course;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.Date;
@Controller
@RequestMapping("/courses")
public class CourseController {
@RequestMapping(value="/{id}", method = RequestMethod.GET)
public Course getCourse(@PathVariable Integer id, ModelMap model) {
return new Course(id, "Spring MVC Content Negotiation XML Example", new Date());
}
}
Demo
Time for a simple demo, the following curl command passes a HTTP “Accept: application/json” header. This means we would like to accept JSON.
curl -H "Accept: application/json" http://localhost:8081/spring-mvc-xml-view-resolver/courses/2
The previous curl command will return the following response.
{
"course":{
"id":2,
"name":"Spring MVC Content Negotiation XML Example",
"date":1463573802406
}
}
The following example demonstrates that when we pass a file extention to the path parameter or if we pass a special request parameter of type XML, we receive the response in XML format.
URL: http://localhost:8081/spring-mvc-xml-view-resolver/courses/2?type=xml or http://localhost:8081/spring-mvc-xml-view-resolver/courses/2.xml