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.
This section provides an overview of the major Spring features, or annotations, that support RESTful web services.
@Controller- Use the
@Controllerannotation to annotate the class that will be the controller in MVC and handle the HTTP request. @RequestMapping- Use the
@RequestMappingannotation 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 themethodparameter 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
@PathVariableannotation.For example:
@RequestMapping(method=RequestMethod.GET, value="/emp/{id}") public ModelAndView getEmployee(@PathVariable String id) { … }
- Other useful annotations
- Use
@RequestParamto inject a URL parameter into the method.Use
@RequestHeaderto inject a certain HTTP header into the method.Use
@RequestBodyto inject an HTTP request body into the method.Use
@ResponseBodyto 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.
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>. |
| MarshallingHttpMessageConverter | Read/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. |
| AtomFeedHttpMessageConverter | Read/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. |
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.
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"}
]}
|
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>
|
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 asgetAllEmp(), but with a differentAcceptheader. - With the
employeeFeed()method you marshall theEmployeeobject 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.
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 HTTPGETmethod and gets the response as an object. -
postForObject: executes the HTTPPOSTmethod with a certain request body. -
put: executes the HTTPPUTmethod with a certain request body. -
delete: executes the HTTPDELETEmethod for a certain URI.
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");
|
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."
| Description | Name | Size | Download method |
|---|---|---|---|
| Article source code | src_code.zip | 11KB | HTTP |
Information about download methods
Learn
- The companion to this article, "Build RESTful web services using Spring 3," (developerWorks, July
2010) introduces the "Spring
way" to build RESTful web services.
- Get an introduction to REST and related links on Wikipedia.
- Go through a Spring MVC showcase to get a good idea of what the technology can
do. It includes a sample project, along with a supporting slide
presentation and screencast.
- Learn all about Spring 3.
- Get more information about RestTemplate APIs.
- Read all about the JAXB Reference Implementation
Project.
- Explore ROME,
a set of Atom/RSS Java utilities that make it easy to work in Java with
most syndication formats.
- Read more about ATOM.
- Read the developerWorks series "Getting to know the Atom Publishing Protocol" (Oct 2006) for a
high-level overview of the protocol and its basic operation and
capabilities.
- Learn about Jackson, the fast, open source
JSON processor.
Get products and technologies
- Get the latest Spring
releases.
- Download
Jackson.
- Download IBM product
evaluation versions or explore
the online trials in the IBM SOA Sandbox and get your hands on
application development tools and middleware products from DB2®, Lotus®,
Rational®, Tivoli®, and WebSphere®.
Discuss
- Create your My developerWorks profile today and set up a watchlist on REST, web services, or Spring. Get
connected and stay connected with My developerWorks.
- Create your My developerWorks profile today and setup a watchlist on REST, web services, or Spring. Get connected
and stay connected with My developerWorks.
- Find other developerWorks members interested in Web development.
- Web developers, share your experience and knowledge in the Web development
group.
- Share what you know: Join one of our developerWorks groups focused on Web
topics.
- Roland Barcia talks about Web 2.0 and middleware in his blog.
- Follow developerWorks' members' shared bookmarks on Web topics.
- Get answers quickly: Visit the Web 2.0 Apps forum.




