Spring MVC Content Negotiation | Java Development Journal

Spring MVC Content Negotiation

This post describes content negotiation in Spring MVC project.We will cover different techniques about Spring MVC Content Negotiation.

 

1. Introduction

There are 2 ways for generating output in our Spring MVC application.

  • For RESTful API, use @ResponseBody annotation.Spring MVC HTTP message converters will return data in the required format (e.g JSON, XML etc.).
  • For the traditional applications, viewResolver used to generate presentation format like HTML.

There is a third possibility which requires both RESTful and traditional web-based data.

For above use cases, it’s desired to know what kind of data format expected in the request body and what is expected in the HTTP response.Spring MVC uses ContentNegotationStrategy to determine what format requested by the user.

 

2. Content Negotiation in Spring MVC

Spring support following content negotiation strategy for determining media or content type of a request.

  • URL path extension (suffix) in the request
    • If URL is https://www.javadevjournal.com/v1/customers.json than JSON is required.
    • If URL ending with .xml than XML is required
  • URL parameter in the request e.g https://www.javadevjournal.com/customers?format=json
  • Accept header in the request.

By default content negotiation works in the same hierarchy as described above.We can customize it based on our need.

 

 

3. Content Negotiation Strategies

Before we start looking into different content negotiation strategies by Spring, let’s do the basic setup by adding required dependencies in pom.xml.

For this post, we will use JSON and XML representation.

<dependencies>
   <!-- for XML support -->
   <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-xml</artifactId>
      <version>2.9.0</version>
   </dependency>
   <!-- for Jackson support -->
   <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.3</version>
   </dependency>
   <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.3</version>
   </dependency>
</dependencies>

 

Spring Boot Configurations

If you are building your application using Spring Boot, please keep in mind following points

  1. Spring Boot provides Jackson dependency using Spring Boot parent POM.

You are free to override version defined in the parent pom using the <exclusion> option in the pom.xml file. pom.xml in Spring Boot will be like 

<dependencies>
   <!-- for XML support -->
   <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-xml</artifactId>
    </dependency>
   <!-- nothing for Jackson -->
</dependencies>

 

3.1 URL Suffix Strategy

This content negotiation strategy in Spring check for the extension (suffix) in the URL to determine desired output content type.

 

3.1.1 Java Configuration

Here is our Java configuration for URL suffix based strategy

@Configuration
@EnableWebMvc
public class RestApiApplication extends WebMvcConfigurerAdapter {

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

    configurer.favorParameter(false).
    ignoreAcceptHeader(false).
    defaultContentType(MediaType.APPLICATION_XML).
    mediaType("xml", MediaType.APPLICATION_XML).
    mediaType("json", MediaType.APPLICATION_JSON);
    }
}

 

3.1.2 XML Configuration
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
   <property name="favorPathExtension" value="true" />
   <property name="favorParameter" value="false" />
   <property name="ignoreAcceptHeader" value="true" />
   <property name="useJaf" value="false" />
   <property name="defaultContentType" value="application/xml" />
   <property name="mediaTypes">
      <map>
         <entry key="json" value="application/json" /&gt;
         <entry key="xml" value="application/xml" />
      </map>
   </property>
</bean>
<!-- Make this available across all of Spring MVC -->
 <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

Let’s check what we did in the configurations

  • Turned off parameter and Accept header based content negotiation.
  • We are setting up XML as default content type.
  • Support both JSON and XML format.

If we run the application,

curl http://localhost:8080/api/rest/customer

Here is the output

<Customer>
   <firstName>Umesh</firstName>
   <lastName>Awasthi</lastName>
   <age>34</age>
   <email>umeshawasthi@javadevjournal.com</email>
   <account>
      <accountId>12</accountId>
      <accountName>Demo</accountName>
      <balance>3456.0</balance>
   </account>
</Customer> 

As the contetType default to XML, system returned XML data in response.If we use JSON extension

curl http://localhost:8080/api/rest/customer.json

Response body

{  
   "firstName":"Umesh",
   "lastName":"Awasthi",
   "age":34,
   "email":"umeshawasthi@javadevjournal.com",
   "account":{  
      "accountId":12,
      "accountName":"Demo",
      "balance":3456.0
   }
}

 

3.2 URL Parameter Strategy

Spring MVC content negotiation also support parameter based strategy.Spring MVC check for the format parameter in the request to find media type.

 

3.2.1 Java Configuration
@Configuration
@EnableWebMvc
public class RestApiApplication extends WebMvcConfigurerAdapter {

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

   configurer.favorPathExtension(false).
   favorParameter(true).
   ignoreAcceptHeader(false).
   useJaf(false).
   defaultContentType(MediaType.APPLICATION_XML).
   mediaType("xml", MediaType.APPLICATION_XML).
   mediaType("json", MediaType.APPLICATION_JSON);
}
 
3.2.2 XML Configuration
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
   <property name="favorPathExtension" value="false" />
   <property name="favorParameter" value="true" />
   <property name="ignoreAcceptHeader" value="true" />
   <property name="useJaf" value="false" />
   <property name="defaultContentType" value="application/json" />
   <property name="mediaTypes">
      <map>
         <entry key="json" value="application/json" />
         <entry key="xml" value="application/xml" />
      </map>
   </property>
</bean>
<!-- Make this available across all of Spring MVC -->
 <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

Let’s check what we did in the configurations

  • Turn off the extension/ suffix and Accept header based content negotiation.
  • We are setting up XML as default content type.
  • Support both JSON and XML format.

If we run the application, 

curl http://localhost:8080/api/rest/customer

Here is the output

<Customer>
   <firstName>Umesh</firstName>
   <lastName>Awasthi</lastName>
   <age>34</age>
   <email>umeshawasthi@javadevjournal.com</email>
   <account>
      <accountId>12</accountId>
      <accountName>Demo</accountName>
      <balance>3456.0</balance>
   </account>
</Customer> 
curl http://localhost:8080/api/rest/customer?format=json

Response body

{  
   "firstName":"Umesh",
   "lastName":"Awasthi",
   "age":34,
   "email":"umeshawasthi@javadevjournal.com",
   "account":{  
      "accountId":12,
      "accountName":"Demo",
      "balance":3456.0
   }
}
 
3.2.3 Change Parameter Name

The name of the parameter is format by default.Spring provides a way to change this parameter.

configurer.parameterName("customParameter")

XML Configuration

..<property name="parameterName" value="mediaType" />..

 

3.2 The Accept Header Strategy

If Accept header is active, Spring MVC look for this header value in the incoming request for the content type.Let’s check the process to enable this approach

 

3.2.1 Java Configuration
@Configuration
@EnableWebMvc
public class RestApiApplication extends WebMvcConfigurerAdapter {

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

   configurer.favorPathExtension(false).
   favorParameter(false).
   ignoreAcceptHeader(false).
   useJaf(false).
   defaultContentType(MediaType.APPLICATION_XML).
   mediaType("xml", MediaType.APPLICATION_XML).
   mediaType("json", MediaType.APPLICATION_JSON);
}
 
3.2.2 XML Configuration
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
   <property name="favorPathExtension" value="false" />
   <property name="favorParameter" value="false" />
   <property name="ignoreAcceptHeader" value="false" />
   <property name="useJaf" value="false" />
   <property name="defaultContentType" value="application/json" />
   <property name="mediaTypes">
      <map>
         <entry key="json" value="application/json" />
         <entry key="xml" value="application/xml" />
      </map>
   </property>
</bean>
<!-- Make this available across all of Spring MVC -->
 <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

Let’s check what we did in the configurations

  • Turn off the extension/ suffix and parameter based content negotiation.
  • Enabled Accept header negotiation.
  • We are setting XML as default content type.
  • Support both JSON and XML format.

 

Summary

In this post, We discussed Spring MVC Content Negotiation strategies. We covered 3 different strategies provided by Spring along with options to customize these strategies.

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of