Spring Content Negotiation

Updated on January 25th, 2019

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

 

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 desire to know what kind of data format expected in the request body and what it expects in the HTTP response. Spring MVC uses ContentNegotationStrategy to determine what format requested by the user.

 

1. How Contents Negotiation Work?

While working on the HTTP request, there are certain ways to perform the content negotiation. One of the most common way in Spring content negotiation is the use of the Accept header property.Client API sets the Accept header to specify the response it expecting.Spring provides certain conventions to make this content negotiation more flexible in case the Accept header is missing or not properly configured.

Read our article on Content Negotiation for more detail.

 

 

2. Content Negotiation in Spring MVC

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

  • URL path extension (suffix) in the request
    • If URL is http://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 http://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 look 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 the 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>[email protected]</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":"[email protected]",
   "account":{  
      "accountId":12,
      "accountName":"Demo",
      "balance":3456.0
   }
}

 

3.2 URL Parameter Strategy

Spring MVC content negotiation also support parameter based strategy. Spring MVC a 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>[email protected]</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":"[email protected]",
   "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 Content Negotiation strategies. We covered 3 different strategies provided by Spring along with options to customize these strategies.

Java Development Journal

Hello!! Welcome to the Java Development Journal. We love to share our knowledge with our readers and love to build a thriving community.

follow me on:

Leave a Reply

avatar

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

  Subscribe  
Notify of