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.

3 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/...

Leave a Reply