Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Build RESTful web services with the Spring 3 MVC HttpMessageConverter feature

Yi Ming Huang, Software Engineer, IBM  
Yi Ming Huang, a Software Engineer at the China Development Lab, works on Lotus Mashups. He has experience on portlet and widget-related web development. Yi is interested in REST, OSGi, and Spring technologies.

Summary:  Spring, the well-known framework for building Java™ Platform, Enterprise Edition (Java EE) applications, now supports Representational State Transfer (REST) in its Model-View-Controller (MVC) layer. It's important for RESTful web services to produce multiple representations based on the client requests. In this article, learn to produce multiple representations with HttpMessageConverter. Code samples show how to use RestTemplate with HttpMessageConverter to communicate with services. Also, learn how to use Spring APIs and annotations to build RESTful web services that produce popular representations such as ATOM Feed, XML, and JavaScript Object Notation (JSON).

Date:  07 Sep 2010
Level:  Intermediate PDF:  A4 and Letter (56KB | 14 pages)Get Adobe® Reader®
Also available in:   Chinese  Korean  Russian  Japanese

Activity:  86682 views
Comments:  

Introduction

A companion article, "Build RESTful web services using Spring 3," (see Resources) introduced the "Spring way" to build RESTful web services. It also explained how to use ContentNegotiatingViewResolver to produce multiple representations, which is an important feature for RESTful web services. This article explains another way to produce multiple representations using HttpMessageConverter, and examples in the article show how to use RestTemplate with HttpMessageConverter to communicate with services.


REST support in Spring MVC

This section provides an overview of the major Spring features, or annotations, that support RESTful web services.

@Controller
Use the @Controller annotation to annotate the class that will be the controller in MVC and handle the HTTP request.
@RequestMapping
Use the @RequestMapping annotation to annotate the function that should handle certain HTTP methods, URIs, or HTTP headers. This annotation is the key to the Spring REST support. You change the method parameter to handle other HTTP methods.

For example:

@RequestMapping(method=RequestMethod.GET, value="/emps", 
headers="Accept=application/xml, application/json")
                    

@PathVariable
A path variable in the URI could be injected as a parameter using the @PathVariable annotation.

For example:

@RequestMapping(method=RequestMethod.GET, value="/emp/{id}")
public ModelAndView getEmployee(@PathVariable String id) { … }
                    

Other useful annotations
Use @RequestParam to inject a URL parameter into the method.

Use @RequestHeader to inject a certain HTTP header into the method.

Use @RequestBody to inject an HTTP request body into the method.

Use @ResponseBody to return the content or object as the HTTP response body.

Use HttpEntity<T> to inject into the method automatically if you provide it as a parameter.

Use ResponseEntity<T> to return the HTTP response with your custom status or headers.

For example:

public @ResponseBody Employee getEmployeeBy(@RequestParam("name") 
String name, @RequestHeader("Accept") String accept, @RequestBody String body) {…} 
public ResponseEntity<String> method(HttpEntity<String> entity) {…}
                    

Refer to the Spring documentation (see Resources) for a complete list of the supported annotations or objects that can be injected into the method.

Multiple representation support

Representing the same resource with different MIME types is an important aspect of RESTful web services. Generally, you would use the same URI with a different "accept" HTTP header to fetch the resource with different representation. You can also use a different URI, or a URI with different request parameters.

"Build RESTful web services using Spring 3" (see Resources) introduced ContentNegotiatingViewResolver, which can pick a different view resolver to handle the same URI (with the difference of the accept header). Thus, ContentNegotiatingViewResolver can be used to produce multiple representations.

There's also another way to produce multiple representations—by combining the HttpMessageConverter and c@ResponseBody annotation. With this method you don't need to use the View technologies.


HttpMessageConverter

HTTP requests and responses are text based, meaning a browser and server communicate by exchanging raw texts. With Spring, however, methods in the controller class return pure 'String' type and domain models (or other Java built-in objects). How can Spring serialize/de-serialize the objects to raw texts? This is handled by HttpMessageConverter. Spring has bundled implementations that can meet your common needs. Table 1 shows some examples.


Table 1. HttpMessageConverter examples
With...You can...
StringHttpMessageConverter Read/write a string from request and response. By default, it supports the media type text/* and writes with a Content-Type of text/plain.
FormHttpMessageConverter Read/write form data from request and response. By default, it reads the media type application/x-www-form-urlencoded and writes data into MultiValueMap<String,String>.
MarshallingHttpMessageConverterRead/write XML data using Spring's marshaller/un-marshaller. It converts data of media type application/xml.
MappingJacksonHttpMessageConverter Read/write JSON data using Jackson's ObjectMapper. It converts data of media type application/json.
AtomFeedHttpMessageConverterRead/write ATOM feed using ROME's Feed API. It converts data of media type application/atom+xml.
RssChannelHttpMessageConverter Read/write RSS feed using ROME's feed API. It converts data of media type application/rss+xml.

Build RESTful web services

In this section, learn to build a simple RESTful web service that can produce multiple representations. Some of the resources used in the sample application were built in "Build RESTful web services using Spring 3" (see Resources). You can also download the sample code.

First, you must configure the HttpMessageConverter. To produce multiple representations, customize several HttpMessageConverter instances to convert the object to different media types. This section covers the JSON, ATOM, and XML media types.

JSON

Let's start with the simplest example. JSON is a lightweight data-interchange format that's easy for humans to read and write. Listing 1 shows the code that configures a JSON converter.


Listing 1. Configure HttpMessageConverter in rest-servlet.xml
<bean class="org.springframework.web.servlet.mvc.annotation
.AnnotationMethodHandlerAdapter">
   <property name="messageConverters">
       <list>
           <ref bean="jsonConverter" />
   <ref bean="marshallingConverter" />
   <ref bean="atomConverter" />
       </list>
   </property>
</bean>

<bean id="jsonConverter" 
            class="org.springframework.http.converter.json
.MappingJacksonHttpMessageConverter">
   <property name="supportedMediaTypes" value="application/json" />
</bean>

In the configuration, three converters are registered. MappingJacksonHttpMessageConverter is used to convert the object to JSON and vice versa. This built-in converter uses Jackson's ObjectMapper to map JSON to the JavaBean, so you must add the following Jackson JAR files to the classpath.

  • org.codehaus.jackson.jar
  • org.codehaus.jackson.mapper.jar

The next step is to write a method to handle the request that asks for JSON representation. Listing 2 shows the details.


Listing 2. Handle JSON requests defined in EmployeeController
                
@RequestMapping(method=RequestMethod.GET, value="/emp/{id}", 
		headers="Accept=application/json")
public @ResponseBody Employee getEmp(@PathVariable String id) {
Employee e = employeeDS.get(Long.parseLong(id));
return e;
}
	
@RequestMapping(method=RequestMethod.GET, value="/emps", 
		headers="Accept=application/json")
public @ResponseBody EmployeeListinggetAllEmp() {
List<Employee> employees = employeeDS.getAll();
EmployeeListinglist = new EmployeeList(employees);
return list;
}
            

The @ResponseBody annotation is used to make the return object (Employee or EmployeeList) the response body content, which will be mapped by MappingJacksonHttpMessageConverter to JSON.

By using HttpMessageConverter and @ResponseBody, you can implement multiple representations without including Spring's View technology -- an advantage over using ContentNegotiatingViewResolver.

Now you can use the CURL or REST Client Firefox plug-in to invoke the request. Remember to add an HTTP header: Accept=application/json. Listing 3 shows the desired response in a JSON format.


Listing 3. JSON result for getEmp() and getAllEmp()


Response for /rest/service/emp/1
{"id":1,"name":"Huang Yi Ming","email":"huangyim@cn.ibm.com"}

Response for /rest/service/emps
{"count":2,
"employees":[
{"id":1,"name":"Huang Yi Ming","email":"huangyim@cn.ibm.com"},
{"id":2,"name":"Wu Dong Fei","email":"wudongf@cn.ibm.com"}
]}
            

XML

Spring's built-in converter MarshallingHttpMessageConverter is used to map between an object and XML (OXM). The example uses JAXB 2 as the marshaller/un-marshaller for the converter. Listing 4 shows the configuration.


Listing 4. Configure MarshallingHttpMessageConverter
                
<bean id="marshallingConverter" 
class="org.springframework.http.converter.xml
		.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxbMarshaller" />
    <property name="supportedMediaTypes" value="application/xml"/>
      </bean>

      <bean id="jaxbMarshaller" 
      class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
      
    <property name="classesToBeBound">
	  <list>
	    <value>dw.spring3.rest.bean.Employee</value>
	    <value>dw.spring3.rest.bean.EmployeeList</value>
	  </list>
    </property>
    
</bean>
            

It's important to understand that JAXB 2 does not have good support for mapping the java.util.List<T> to XML. Common practice is to add a wrapper class for the collection of objects. Refer to "Build RESTful web services using Spring 3" (see Resources) or download the source code for details of this JAXB annotated class.

What about the method in the controller that handles the request? Take a look back at the code in Listing 2. It's not surprising to find that you don't need to add any code here. You just need to add another supported media type in the Accept header, as follows.

headers=”Accept=application/json, application/xml”
            

The converter will map the object properly to the type you request (JSON or XML). Listing 5 shows the desired result when you request the application/xml representation.


Listing 5. XML result for getEmp() and getAllEmp()
                     
Response for /rest/service/emp/1
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <employee>
   <email>huangyim@cn.ibm.com</email>
   <id>1</id>
   <name>Huang Yi Ming</name>
 </employee>
Response for /rest/service/emps
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <employees>
  <count>2</count>
    <employee>
      <email>huangyim@cn.ibm.com</email>
      <id>1</id>
      <name>Huang Yi Ming</name>
    </employee>
    <employee>
      <email>wudongf@cn.ibm.com</email>
      <id>2</id><name>Wu Dong Fei</name>
    </employee>
 </employees>
            

ATOM feed

An ATOM feed is another popular format for exchanging data in RESTful web services. An Atom feed document is a representation of an Atom feed, including metadata about the feed, and some or all of the entries associated with it. Its root is the atom:feed element. There is also an ATOM Publish Protocol (APP) to define the exchange format and behaviors. (Defining the ATOM and APP formats is outside the scope of this article. See Resources for more information.)

The example uses AtomFeedHttpMessageConverter to convert the ATOM feed, which leverages the ROME ATOM API. Therefore, you must include the JAR file sun.syndication.jar in your classpath. Listing 6 shows the configuration of this converter.


Listing 6. Configure AtomFeedHttpMessageConverter
                
<bean id="atomConverter" 
class="org.springframework.http.converter.feed
		.AtomFeedHttpMessageConverter">
<property name="supportedMediaTypes" value="application/atom+xml" />
</bean>
            

Listing 7 shows the code that handles the ATOM request and the feed generation.


Listing 7. getEmpFeed() in EmployeeController & AtomUtil class
                
@RequestMapping(method=RequestMethod.GET, value="/emps", 
		headers="Accept=application/atom+xml")
public @ResponseBody Feed getEmpFeed() {
	List<Employee> employees = employeeDS.getAll();
	return AtomUtil.employeeFeed(employees, jaxb2Mashaller);
}

public static Feed employeeFeed(
	List<Employee> employees, Jaxb2Marshaller marshaller) {
Feed feed = new Feed();
feed.setFeedType("atom_1.0");
feed.setTitle("Employee Atom Feed");
		
List<Entry> entries = new ArrayList<Entry>();
for(Employee e : employees) {
	StreamResult result = new StreamResult(
	new ByteArrayOutputStream());
	marshaller.marshal(e, result);
	String xml = result.getOutputStream().toString();
			
	Entry entry = new Entry();
	entry.setId(Long.valueOf(e.getId()).toString());
	entry.setTitle(e.getName());
	Content content = new Content();
	content.setType(Content.XML);
	content.setValue(xml);
	
	List<Content> contents = new ArrayList<Content>();
	contents.add(content);
	entry.setContents(contents);
	entries.add(entry);
}
feed.setEntries(entries);
return feed;
}
            

In the code above, notice:

  • The getEmpFeed() method handles the same URI as getAllEmp(), but with a different Accept header.
  • With the employeeFeed() method you marshall the Employee object to XML and then add it to the <content> element of the feed entry.

Listing 8 shows the output when you request application/atom+xml representation for URI /rest/service/emps.


Listing 8. Output for /rest/service/emps when request application/atom+xml
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Employee Atom Feed</title>

 <entry>
    <title>Huang Yi Ming</title>
    <id>1</id>
  <content type="xml">
    <employee>
            <email>huangyim@cn.ibm.com</email>
            <id>1</id>
            <name>Huang Yi Ming</name>
    </employee>
  </content>
</entry>

  <entry>
    <title>Wu Dong Fei</title>
    <id>2</id>
  <content type="xml">
    <employee>
            <email>wudongf@cn.ibm.com</email>
            <id>2</id>
            <name>Wu Dong Fei</name>
     </employee>
   </content>
 </entry>
 
</feed>
 

Implement POST, PUT, and DELETE

The examples thus far have implemented several methods to handle the HTTP GET method. Listing 9 shows implementation of the POST, PUT, and DELETE methods.


Listing 9. POST, PUT, and DELETE methods in EmployeeController
@RequestMapping(method=RequestMethod.POST, value="/emp")
public @ResponseBody Employee addEmp(@RequestBody Employee e) {
employeeDS.add(e);
return e;
}
	
@RequestMapping(method=RequestMethod.PUT, value="/emp/{id}")
public @ResponseBody Employee updateEmp(
	@RequestBody Employee e, @PathVariable String id) {
employeeDS.update(e);
return e;
}
	
@RequestMapping(method=RequestMethod.DELETE, value="/emp/{id}")
public @ResponseBody void removeEmp(@PathVariable String id) {
employeeDS.remove(Long.parseLong(id));
}
            

The @RequestBody annotation is used in the addEmp() and updateEmp() methods. It takes the HTTP request body and tries to convert it to the object class using the registered HttpMessageConverter. In the next section, you'll use RestTemplate to communicate with these services.


Use RestTemplate to communicate with REST services

"Build RESTful web services using Spring 3" (see Resources) introduced how to use CURL and the REST client to test REST services. At the programming level, Jakarta Commons' HttpClient is typically used to do so (but that's outside the scope of this article). You can also use a Spring REST client called RestTemplate. It is conceptually similar to other template classes in Spring, such as JdbcTemplate and JmsTemplate.

RestTemplate also uses the HttpMessageConverter. You could pass the object class in the requests and let the converters handle the mappings.

Configuring the RestTemplate

Listing 10 shows the configuration of RestTemplate. It also uses the three converters introduced previously.


Listing 10. Configure RestTemplate

<bean id="restTemplate" 
class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
	<list>
	<ref bean="marshallingConverter" />
	<ref bean="atomConverter"  />
	<ref bean="jsonConverter" />
	</list>
</property>
</bean>
            

The examples in this article used only some of the methods that could simplify communication between servers. RestTemplate supports other methods, including:

  • exchange: executes certain HTTP methods with request body and gets the response.
  • getForObject: executes the HTTP GET method and gets the response as an object.
  • postForObject: executes the HTTP POST method with a certain request body.
  • put: executes the HTTP PUT method with a certain request body.
  • delete: executes the HTTP DELETE method for a certain URI.

Code samples

The following code samples help illustrate how to use RestTemplate. Refer to the RestTemplate API (see Resources) for a detailed explanation of the APIs used.

Listing 11 shows how to add headers to the request and then to invoke the request. Using the MarshallingHttpMessageConverter you could get the response and convert it to the typed class. You can use different media types to test other representations.


Listing 11. Request for XML representation
                
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<EmployeeList> response = restTemplate.exchange(
"http://localhost:8080/rest/service/emps", 
HttpMethod.GET, entity, EmployeeList.class);
EmployeeListingemployees = response.getBody();
// handle the employees
            

Listing 12 shows how to POST a new employee to the server. The server-side service addEmp() could accept data with media types of application/xml and application/json.


Listing 12. POST a new employee
                
Employee newEmp = new Employee(99, "guest", "guest@ibm.com");
HttpEntity<Employee> entity = new HttpEntity<Employee>(newEmp);
ResponseEntity<Employee> response = restTemplate.postForEntity(
"http://localhost:8080/rest/service/emp", entity, Employee.class);
Employee e = response.getBody();
// handle the employee
            

Listing 13 shows how to PUT a modified employee to update the original one. It also shows the feature you can use as a place holder ({id}) in the request URI.


Listing 13. PUT to update an employee
                
Employee newEmp = new Employee(99, "guest99", "guest99@ibm.com");
HttpEntity<Employee> entity = new HttpEntity<Employee>(newEmp);
restTemplate.put(
	"http://localhost:8080/rest/service/emp/{id}", entity, "99");

Listing 14 shows how to DELETE an existing employee.


Listing 14. DELETE an existing employee
restTemplate.delete(
	"http://localhost:8080/rest/service/emp/{id}", "99");


Summary

In this article, you learned about the HttpMessageConverter that was introduced in Spring 3. It provides both client and server-side support for multiple representations. Using the source code provided, you can explore the differences between the implementation of HttpMessageConverter in this article and the implementation using ContentNegotiatingViewResolver in "Build RESTful web services using Spring 3."



Download

DescriptionNameSizeDownload method
Article source codesrc_code.zip11KBHTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Yi Ming Huang, a Software Engineer at the China Development Lab, works on Lotus Mashups. He has experience on portlet and widget-related web development. Yi is interested in REST, OSGi, and Spring technologies.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, SOA and Web services
ArticleID=514033
ArticleTitle=Build RESTful web services with the Spring 3 MVC HttpMessageConverter feature
publish-date=09072010
author1-email=huangyim@cn.ibm.com
author1-email-cc=bwetmore@us.ibm.com

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers