Spring 3.0: REST services with Spring MVC

Spring 3.0 has support for REST style WebServices, the Spring MVC controllers facilitate the functionality. In this example I will show an example of how to implement a basic REST service that uses XML marshalling to sent information over HTTP. Disclaimer: this is not an in depth tutorial for building REST style WebServices.

The Spring MVC controller

The Spring 3.0 REST support relies havily on Spring MVC. You need to use the Spring MVC Controller for implementing REST style WebServices with Spring. To declare a Controller you can use the Spring annotation based configuration. In this example I have annotated the ProductRestService class with the @Controller annotation. In order for Spring to pick-up the annotation Spring needs to be configured to scan for annotation (see the Spring configuration section).

REST uses templates that describe the URI to be used to invoke a WebService method. These URI templates can contain variable placeholders which allow for passing information to the WebService. The URI template contains all the information required for invoking a RESTfull GET method.

The @RequestMapping annotation allowes you to define the URI and HTTP method that are mapped to a method. In this example I have annotated the ProductRestService.getProductById(Long productId) with the @RequestMapping.
The value of the @RequestMapping, in this case: /products/{productId} , defines the URI that is mapped to this method. The productId variable needs to be defined when invoking the method and will be resolved automatically by Spring MVC with the value from the request URI. You can use the @PathVariable to inject the value of the productId variable directly into a method parameter.

The @ResponseBody annotation tells Spring to marshall the return value of the method to the HTTP response body. Spring allowes you to configure HTTP message converters that take care of conversion of the return value to a format which is accepted by the client. In this example the return value will be marshalled to XML using XStream.

package com.oudmaijer.spring.rest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 *  This is an example REST style MVC controller. It serves as an
 *  endpoint for retrieving Product Objects.
 */
@Controller
public class ProductRestService {

    /**
     * This method returns a specific Product. The URI to request a Product is 
     * specified in the @RequestMapping.
     *
     * @param productId the identifier of the requested product
     * @return a Product
     */
    @RequestMapping(value="/products/{productId}", method = RequestMethod.GET)
    @ResponseBody
    public Product getProductById(@PathVariable Long productId) {
        Product p = new Product();
        p.setId(productId);
        return p;
    }
    
}

Spring configuration

The configuration is where all the magic happens. It is important to define the <mvc:annotation-driven /> element at the end of the configuration file or else Spring will not register the marshallingHttpMessageConverter. It took me some time to figure this out ;(

You need to add the MessageConverters to the configuration in order to get the OXM marshalling to work. Spring uses the requests Accept header to determine which converter to use.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

	<!-- Enable annotation scanning. -->
	<context:component-scan base-package="com.oudmaijer.spring.rest" />

	<!-- Define the OXM marshaller which is used to convert the Objects <-> XML. -->
	<bean id="oxmMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller" />

	<bean id="marshallingHttpMessageConverter"
		class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
		<property name="marshaller" ref="oxmMarshaller" />
		<property name="unmarshaller" ref="oxmMarshaller" />
	</bean>

	<!-- Required for REST services in order to bind the return value to the ResponseBody. -->
	<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="messageConverters">
			<util:list id="beanList">
				<ref bean="marshallingHttpMessageConverter" />
			</util:list>
		</property>
	</bean>

	<!-- Should be defined last! -->
	<mvc:annotation-driven />

</beans>

Maven2 dependencies

You need to add a couple of Maven2 dependencies to get the project up and running. Below is the entire pom.xml.

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.oudmaijer.spring.rest</groupId>
    <artifactId>spring-3.0-rest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <!-- http://maven.apache.org/plugins/maven-compiler-plugin/ -->
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
            <optional>false</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.0.0.RELEASE</version>
            <optional>false</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>3.0.0.RELEASE</version>
            <optional>false</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>3.0.0.RELEASE</version>
            <optional>false</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>3.0.0.RELEASE</version>
            <optional>false</optional>
        </dependency>
        <dependency>
            <groupId>xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.2.2</version>
            <optional>false</optional>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>        
    </dependencies>
</project>

Web deployment descriptor: web.xml

Last but not least the web.xml. Since the REST support in Spring is based on Spring MVC you need to define the DispatcherServlet. Make sure to map the correct URL pattern to the DispatcherServlet.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    id="WebApp_ID" version="2.5">
  <display-name>spring-3.0-rest</display-name>
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/META-INF/spring/*.xml</param-value>
  </context-param>
  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
      <servlet-name>DispatcherServlet</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value></param-value>
      </init-param>
  </servlet>
  <servlet-mapping>
      <servlet-name>DispatcherServlet</servlet-name>
      <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

Invoking the service

This example only supports the HTTP GET method. If you want to test or build a client that uses REST WebServices you should use the RestTemplate in Spring. We can easily validate if the example WebService is running by accessing the service through Firefox. This will result in the following response.

For more information on REST support in Spring 3.0 please refer to the Spring reference documentation.

22 Responses to “Spring 3.0: REST services with Spring MVC”

  1. loci says:

    nice article!
    I’ll add that in order to have well formed xml in the browser you may add aliases:
    http://static.springsource.org/spring-ws/sites/1.5/reference/html/oxm.html

    so you will have for example instead of

    on the other hand, I’d like to know how do you proceed for unitary tests ? i use jersey but there may be another solution

  2. [...] Spring 3.0: REST services with Spring MVC « oudmaijer.com | – Spring 3.0 has support for REST style WebServices, the Spring MVC controllers facilitate the functionality. In this example I will show an example of how to implement a basic REST service that uses XML marshalling to sent information over HTTP [...]

  3. Social comments and analytics for this post…

    This post was mentioned on Twitter by viskovic: http://www.oudmaijer.com/blog/2010/01/16/spring-3-0-rest-services-with-spring-mvc/

  4. a developer says:

    You saved my day. Thanks.

  5. czerwiu says:

    How can I fine tune the url mapping in web.xml? How to configure it if I want the DispatcherServlet to serve only requests that come from “/products/*” pattern? In case of “/*” pattern everything goes through this servlet. If I put “/products/*” pattern in url-pattern in web.xml it keeps saying that no mapping is found for HTTP request.

    • soudmaijer says:

      That is because the URL`s in the Spring controller are relative to the Servlet mapping. So if you change the web.xml to /products/* you also need to change the mapping in the controler to /{productId}

      If not the request is accessible through: /products/products/etc

  6. swa says:

    how do i run this? what is the URL path?

  7. Ajay says:

    Nice & useful article

  8. Tin says:

    Nice article, Question..?

    If I want the method “getProductById” to return in the different format such as XML or JSON. For example:

    I will call the method like below:

    Returning in XML
    http://localhost:8080/spring-3.0-rest/product/1.xml

    Returning in JSON
    http://localhost:8080/spring-3.0-rest/product/1.json

    Could you please guide how to do in spring 3 and thanks for sharing.

    • soudmaijer says:

      Hi Tin,

      suffixing the response return type is typically not the way to go with RESTful services. RESTful services typically return a specific format based on the Content Negotiation of the Client and the Server (http://en.wikipedia.org/wiki/Content_negotiation). You define what response type you expect by setting the HTTP Accept header to application/xml or application/json. Spring uses a ContentNegotiatingViewResolver for this.

      Also have a look at this article: http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/

      Summary

      Basically, your service has 1 URL: http://localhost:8080/spring-3.0-rest/product/1 and based on the Accept header it returns either XML or JSON. You do not need 2 methods in your controller, just two Marshallers on for XML and one for JSON. This can be done based on JAXB annotations and Jackson.

      If you still experience problems, let me know!

  9. Tin says:

    Thanks for your reply, That’s really helpful for me to learn more. I also got the answer from spring forum and both of you make me clear about how to make REST and RESTFul in spring 3.

  10. Krishna says:

    Good basic article on spring rest services. Spring REST services

    • soudmaijer says:

      Hi Krishna,

      the article you are refering to uses JAX-RS (Jersey) and not Spring MVC based RESTful services.

  11. Kris says:

    Can you please send me the War file without the jars?

    I have setup it but getting error like below for my url
    description The requested resource (/ProjTmplWar/ocn/1/oppoId/2) is not available.

    • soudmaijer says:

      Looks like old files that are still referenced in your workspace. Are you using Eclipse? Try cleaning the project.

  12. Renata Roginsky says:

    Thank you, thank you, thank you. And thank you again. I spent the whole day today trying to get it to work, and I’ve no idea how much longer I would be banging my head on the wall if
    I didn’t find your article.

  13. Gerard says:

    Hi soudmaijer,

    First of all thanks for your post. This post help me to learn Rest services with Spring 3.

    I try to develop exactly the same example but when I deploy the example and navigate to: http://localhost:8080/restservice/products/1, I have a HTTP ERROR: 406, NOT_ACCEPTABLE.

    Anyone can help me?

    Thanks!

    • soudmaijer says:

      Hi Gerard,

      406 has something to do with incorrect Accept of the Content Type. What browser are you using?

      Cheers, Stephan

  14. If you’re interested in generating documentation for a standard Spring 3 RESTful service, you should check out RESTdoclet (recently outsourced by IG Group). More info and links here: http://soaprobe.blogspot.co.uk/2012/07/rest-service-documentation-using.html

    Robert

  15. Kris J says:

    I am trying to return a PDF document that has been generated by the backend. I do not wish for any Spring Conversion to happen, what should my ContentNegotiatingViewResolver and MarshallingView look like?

    -thank you.