Dec 01 2009

Spring 3.0 RESTful Web Services By Example

Published by at 6:47 pm under Java,REST,Spring

Update:See this post for an updated code example that works with Spring 3.0.1.RELEASE.

If you’re reading this then you’re probably aware that the new Spring 3.0 release will have REST support (If you’re not familiar with REST here is a nice intro).  In this article I’m going to describe the basic steps required to quickly get a RESTful XML web service going using the latest Spring 3 release candidate (3.0.0.RC3).  In future follow-up articles I will describe how to switch between JSON and XML using selectors and how to use the Spring REST Template to read RESTful web services.

Before I get started I’m going to need to make some assumptions about you, the reader.  This is not a beginner Spring, MVC, or Java EE tutorial, so in order to keep the length of this article reasonable I need to assume certain knowledge.  First, I’m hoping that you are familiar with basic Spring 2.5.3+ IoC fundamentals.  It would also be very helpful to understand Spring MVC fundamentals as well.  You’ll also need to be familiar with the structure and configuration of a Java EE web project.  Finally, if you plan to download and use the example code, it’s necessary to know enough about Maven to be able to build a project.

Getting Spring 3.0.0.RC3

Obviously before you do anything you need to get the Spring 3 binaries.  I recommend using Maven to handle the Spring JARs and their dependencies.  This article will assume that you are using Maven. However, if you are a Maven holdout then you can download the binaries and put them in your classpath manually if you wish. Since 3.0.0 has not been released yet, the only way to give Maven access to it is via Spring’s bundle repositories. I find that the easiest way to do this is to include the repository entries in my settings.xml file, but you can also put them in the POM file for your project or even add them to Nexus as proxy repositories if you are in such an environment. The entries should look like this:

...
<repositories>
   <repository>
      <id>SpringSource Enterprise Bundle Repository – External Bundle Milestones</id>
      <url>http://repository.springsource.com/maven/bundles/milestone</url>
   </repository>
   <repository>
      <id>SpringSource Enterprise Bundle Repository – SpringSource Bundle Releases</id>
      <url>http://repository.springsource.com/maven/bundles/release</url>
   </repository>
   <repository>
      <id>SpringSource Enterprise Bundle Repository – External Bundle Releases</id>
      <url>http://repository.springsource.com/maven/bundles/external</url>
   </repository>
</repositories>
...

With these entries in place Maven should now be able to import Spring 3.0 binaries and certain other useful bundles.

Configuring the POM file

I’m using the following dependencies. If you’re using Maven you can probably get away with not declaring all of them. If you’re not using Maven you may find that there are some that you still need. That’s because Maven does transitive dependency management for you. The thing to note here is that, starting with Spring 3.0, there is no “everything jar”, so you have to figure out what JARs you’ll need for a particular functionality.

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>org.springframework.context</artifactId>
   <version>${spring.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>org.springframework.core</artifactId>
   <version>${spring.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>org.springframework.web</artifactId>
   <version>${spring.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>org.springframework.web.servlet</artifactId>
   <version>${spring.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>org.springframework.beans</artifactId>
   <version>${spring.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>org.springframework.oxm</artifactId>
   <version>${spring.version}</version>
</dependency>
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>com.springsource.javax.servlet</artifactId>
   <version>${servlet-api.version}</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>com.stupidjavatricks.spring</groupId>
   <artifactId>spring-rest-example-model</artifactId>
   <version>1.0</version>
</dependency>
<dependency>
   <groupId>com.google.collections</groupId>
   <artifactId>google-collections</artifactId>
   <version>1.0-rc4</version>
</dependency>

The Book Search Service

I’ve tried to keep the example as simple as possible without being too trivial. I chose a book search as it seemed fairly simple. The idea is to use a search service to return a POJO or a list of POJOs of some kind (e.g. Book.java) in response to a query. In this example I’m searching for books or authors. If the class structure doesn’t seem that well thought out, that’s because it’s not; it’s just an example. It also might not meet your definition of “RESTful.” If that’s the case then I apologize in advance for ruining your day. 😉

Book.java

@XStreamAlias("book")
public class Book {
 
	private String isbn;
	private String title;
	private int edition;
	private int pages;
	private String published;
	private List authors;
	private Publisher publisher;
    ...
}

Author.java

@XStreamAlias("author")
public class Author {
 
	private String authorId;
	private String name;
	private String email;
    ...
}

Publisher.java

@XStreamAlias("publisher")
public class Publisher {
 
	private String name;
	private Address address;
    ...
}

Address.java

@XStreamAlias("address")
public class Address {
 
	private String address;
	private String city;
	private String state;
	private String zip;
    ...
}

You’ll notice that there’s not much interesting about any of these classes save for the annotations. The @XStreamAlias annotation is used by XStream to tell it what to name the XML element representing a class. The default is to use a fully-qualified class name (e.g. <com.stupidjavatricks.books.Book>), which can get verbose and also exposes the underlying class. If you don’t mind about either of those things then you don’t need to worry about using the annotations.

My ultra-simple search interface looks like this:

BookService.java

public interface BookService {
	public Book getBookByIsbn(String isbn);
	public List getBooksByAuthor(String authorId);
	public List getAllBooks();
	public List getAllAuthors();
	public Author getAuthorById(String authorId);
}

My implementation is not important, but for simplicity and portability I’ve chosen mock data. You can implement your own to use a database or whatever you like.

The Controller

The controller for this example is just a plain old Spring MVC annotated controller with one difference: @PathVariable. This annotation binds URL template variables to method parameters. It is described in more detail in an article by Arjen Poutsma of the Spring team.

BookServiceController.java

@Controller
public class BookServiceController {
 
	@Autowired
	BookService bookService;
 
	@RequestMapping(value = "/books/")
	public ModelAndView getAllBooks() {
		List books = bookService.getAllBooks();
		ModelAndView mav =
			new ModelAndView("bookXmlView", BindingResult.MODEL_KEY_PREFIX + "books", books);
		return mav;
	}
 
	@RequestMapping(value = "/books/{isbn}")
	public ModelAndView getBookByIsbn(@PathVariable String isbn) {
		Book book = bookService.getBookByIsbn(isbn);
		ModelAndView mav =
			new ModelAndView("bookXmlView", BindingResult.MODEL_KEY_PREFIX + "book", book);
		return mav;
	}
 
	@RequestMapping(value = "/authors/")
	public ModelAndView getAllAuthors() {
		List authors = bookService.getAllAuthors();
		ModelAndView mav =
			new ModelAndView("bookXmlView", BindingResult.MODEL_KEY_PREFIX + "authors", authors);
		return mav;
	}
 
	@RequestMapping(value = "/authors/{authorId}")
	public ModelAndView getAuthorById(@PathVariable String authorId) {
		Author author = bookService.getAuthorById(authorId);
		ModelAndView mav =
			new ModelAndView("bookXmlView", BindingResult.MODEL_KEY_PREFIX + "author", author);
		return mav;
	}
 
	@RequestMapping(value = "/authors/{authorId}/books")
	public ModelAndView getBooksByAuthor(@PathVariable String authorId) {
		List books = bookService.getBooksByAuthor(authorId);
		ModelAndView mav =
			new ModelAndView("bookXmlView", BindingResult.MODEL_KEY_PREFIX + "books", books);
		return mav;
	}
}

Once again: nothing out of the ordinary. I’m simply using the @RequestMapping annotation to bind URL templates to methods and then using an injected BookService to do the work. I’m also returning a model and view. Something to note is that I’m prefixing the name of the model object with the constant BindingResult.MODEL_KEY_PREFIX. This is necessary because of what seems to be a bug in the MarshallingView.java class. Then again, maybe it’s undocumented behavior. Either way – including this prefix will save you headaches.

Wiring it up

Now that I’ve got my model classes created and my controller created and annotated, I’ll need to do a little configuration. The first thing I want to configure is the web.xml file. I need to add a Servlet and Servlet mapping.

WEB-INF/web.xml (excerpt)

...
<servlet>
   <servlet-name>books</servlet-name>
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
   <load-on-startup>1</load-on-startup>
</servlet>
 
<servlet-mapping>
   <servlet-name>books</servlet-name>
   <url-pattern>/booksearch/*</url-pattern>
</servlet-mapping>

Here I’ve created a Spring DispatcherServlet named books and mapped it to the /booksearch/* URL pattern. Nothing new here. Now I need to configure the Spring context XML file for this Servlet.

WEB-INF/books-servlet.xml (excerpt)

...
<bean id="bookXmlView"
   class="org.springframework.web.servlet.view.xml.MarshallingView">
   <constructor-arg>
      <bean class="org.springframework.oxm.xstream.XStreamMarshaller">
         <property name="autodetectAnnotations" value="true"/>
      </bean>
   </constructor-arg>
</bean>
...

Pretty standard. As you can see I’m scanning the com.stupidjavatricks.restexample package for annotated classes. I’m using a BeanNameViewResolver to keep the example simple, but you could get much more complex behavior using other ViewResolvers including a new favorite of mine: ContentNegotiatingViewResolver. The view I’m adding here is a MarshallingView, which takes POJOs and marshals them to XML, automatically. In order for this to work, I need to pass a Marshaller object to the MarshallingView constructor. I chose XStreamMarshaller because I’m familiar with XStream, but you could choose any of the other implementations including CastorMarshaller, XmlBeansMarshaller, etc (Something to note about these marshallers is that they implement both the Marshaller and UnMarshaller interfaces.). You’ll notice that I set the autodetectAnnotations property to true. This will allow XStream to take advantage of any annotated classes on the classpath. This convenience comes at a price however, so if you wish you can explicitly tell XStream which annotated classes to look for. You would do this in the Spring XML context by removing the autodetectAnnotations property and passing a list of classes to the annotatedClasses property. Check the XStreamMarshaller API for more configuration settings.

Testing

You can build and run this any number of ways. I use Maven to build and Apache Tomcat to run it.

You can download the code here.

From the spring-rest-example-model project directory you can run mvn install. Then from within the spring-rest-example project directory mvn package. Check the target directory of the last project for the WAR file and deploy it to the Tomcat webapps directory and start the server. For a list of all authors and all books in this example you can browse to http://localhost:8080/spring-rest-example/booksearch/authors/ and http://localhost:8080/spring-rest-example/booksearch/books/ respectively.

Problems?

If you are having trouble getting the code to import or compile try one or both of the following:

  1. Go to Window->Preferences->Maven->Installations and choose your local Maven installation rather than the embedded Maven. I find that this reduces a some of the strange errors I used to get.
  2. Import spring-rest-example-model first and do a mvn install before importing spring-rest-example. I’ve noticed that Eclipse or STS will often throw a NullpointerException if I don’t follow these steps and attempt to import both projects at the same time.


31 responses so far

31 Responses to “Spring 3.0 RESTful Web Services By Example”

  1. Tonyon 02 Dec 2009 at 6:17 am

    If you had trouble getting the example code to build, that’s because I forgot to include the Java version variable in the spring-rest-example-model project. It should work now.

  2. Adamon 04 Dec 2009 at 7:33 am

    Take a look at @ModelAttributte annotation. It might help you get rid of ModelAndView classes in every method.

  3. Andreason 04 Dec 2009 at 8:19 am

    Very good blog Tony!

  4. Solomonon 06 Dec 2009 at 2:10 pm

    There are a bit of syntactic sugar that you could do here with @ResponseBody. IMHO, it would also be idea to show a POST or PUT used with @RequestBody.

  5. Victor Liangon 14 Dec 2009 at 10:51 am

    we are looking for someone to teach REST via online webcast. It will be 1.5 hours per week for about 10-15 weeks. Flexiblie hour based on your availability. If you are interested, please contact me.

    Victor Liang

  6. Anonymouson 18 Dec 2009 at 5:56 am

    Nice Spring 3.0 REST support sample.

    Since Dec 16th, Spring 3.0 is available on Maven central repository. (and servlet API 2.5 is available on central repository too).
    No need to include additional definition.

    Do note that with final 3.0.0, the artefact names are : spring-xxx.

    I would suggest to actualize your pom to this : http://flex.scoutant.org/assets/pom.xml

    spring-rest-example-model directory is unchanged : just run: ‘mvn install’
    Then, in dir spring-rest-example, with the actualise pom, you can run ‘mvn install’.

  7. Tonyon 18 Dec 2009 at 6:32 am

    Thanks. Yes, this blog was written on Dec 1. I’m now evaluating the GA release. There was a “show-stopper” bug in RC3 that forced me to back up to RC2, so I need to ensure it was fixed first.

    For anyone not wishing to go through the trouble of changing all of your Spring dependencies in your POM, you can continue to use the Spring bundle repositories. All you need to do is change add the following “release” repository to your POM and then change your “spring.version” property to “3.0.0.RELEASE”.

    <repository>
      <id>com.springsource.repository.bundles.release</id>
      <name>SpringSource Enterprise Bundle Repository - Release</name>
      <url>http://repository.springsource.com/maven/bundles/release</url>
    </repository>
  8. Rick Herrickon 30 Dec 2009 at 1:21 pm

    IRT using Maven Central version of Spring dependencies, there are real reasons to use the EBR versions, primarily that the Spring EBR versions are tested by SpringSource QA and are also OSGi-enabled bundles (Maven Central are not OSGi-enabled).

    The artifact names being spring-xxx are not related to the 3.0.0.RELEASE update, but instead to difference in naming conventions between Maven Central and Spring EBR versions. The names map like this:

    Maven Central: spring-xxx
    Spring EBR: org.springframework.xxx

    The exception that I know of is spring-webmvc, which maps to org.springframework.web.servlet.

    One other note: I had to explicitly add XStream to my pom.xml:

    	com.thoughtworks.xstream
    	xstream
    	1.3.1
    
  9. Rick Herrickon 30 Dec 2009 at 1:23 pm

    I also meant to add, great article! This presented the basics for Spring 3.0 REST simply and clearly. Other than getting the correct version of XStream (I had 1.2.2 to start, which doesn’t have the autodetectAnnotations property!), my own custom example ran on the first try!

  10. Paton 04 Feb 2010 at 7:11 am

    Thanks very much for the example. I’m trying to integrate a C#.NET client against the REST service exposed by this example.

    I want to change the response header to UTF-8.

    I’ve been through a lot of forums that seem to think that the Dispatcher Servlet is hard-coded to ISO-8859-1, as follows:-

    Content-Type: application/xml;charset=ISO-8859-1

    Please let me know if we have any control over this at Controller level.

    Thanks

    Pat

  11. Tonyon 04 Feb 2010 at 10:17 am

    @Pat: I think this may be an issue of the platform you are using (Windows right?). Anyway, I found several ways to change the charset, but the one I’m going to mention seems like the best option. Look at the Spring config file with the MarshallingView bean. Add the following property:

    <property name=”contentType” value=”application/xml;charset=UTF-8″/>

    This changes the entire Content-Type header, but that’s fine in this case since you know you want XML. It might also be a good idea to change the charater encoding of your SML marshaller – in my example the XStreamMarshaller.

    <property name=”encoding” value=”UTF-8″/>

    Give these a try.

  12. Leeon 14 May 2010 at 3:06 pm

    Hi,

    I built the war and deployed into tomcat 6.0.18. The java version is 1.6. After it is deployed, I got 404 books servlet not available.

    Please help

  13. Leeon 14 May 2010 at 3:16 pm

    Got it working using your later release sample.

  14. Dygnsprognoson 31 May 2010 at 2:43 pm

    Supernice article! Made it very easy to setup a project and get it running.

  15. nickon 29 Jun 2010 at 2:34 am

    does the annotation only works with Spring MVC or does it support in Struts2 ?

  16. Bienvenido Davidon 20 Jul 2010 at 1:43 pm

    I wasn’t looking for a web service but an example on how to configure web.xml and the controller with @PathVariables. Your example above helped a lot. Thanks.

  17. Minh Doon 17 Aug 2010 at 12:39 pm

    Nice post!! It saved me a great deal of time when you mentioned including the prefix: BindingResult.MODEL_KEY_PREFIX. We were using Jaxb marshaller/unmarshaller and as soon as switching to XStream, the bug showed up. Spring needs to fix this. Thanks a lot Tony.

  18. Vivekon 03 Feb 2011 at 12:10 am

    Hi Tony, Great post, but how to maintain version there, if we require any changes in existing service, so how we are going to maintain versions.

  19. Michaelon 13 Mar 2011 at 5:25 pm

    Hi, I implemented this example and everything is working fine except for the receiving the result. When I send the request from browser I end up with (I’ll copy the start of the stacktrace).

    javax.servlet.ServletException: Could not resolve view with name ‘books’ in servlet with name ‘books’
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1042)

    I must say that I’m new at spring so I might be forgetting something logical?

    Thanks in advance

  20. Jacomoon 18 Mar 2011 at 6:47 pm

    Great example. I was wondering if it’s possible to create a Spring 3 REST service without having to define anything in XML, of course other than web.xml?

    For example, you have a couple of defined in books-servlet.xml. Can this be defined in a Spring Java-based config?

    Thanks,

    Jac

    PS: BTW, the maven build failed at trying to download: com.springsource.javax.servlet-2.5.0.jar.

  21. Yudhi Karunia Surtanon 14 Apr 2011 at 7:15 am

    Nice Article, i was developing a similar things using spring and jersey, but think i think using spring 3 is a lot more faster to develop.
    Thanks for share.

  22. Priya Dandekaron 28 Apr 2011 at 5:07 pm

    Excellent post, I used this for my roo app to be more smarter.

    Thanks for posting this.

  23. Marcus Hugheson 26 Jun 2011 at 5:47 am

    Great article – thanks. You have distilled the essence of configuring a simple REST service. Most of all, your example worked perfectly the first time. Thanks.

    Just need to get Spring security around it now!

  24. Barryon 20 Jul 2011 at 12:51 pm

    I made a few changes, but basically I think I have the same structure, and I get:

    13:49:45,474 ERROR [[SpringREST]] – Servlet.service() for servlet SpringREST threw exception
    javax.servlet.ServletException: Circular view path [XMLview]: would dispatch back to the current handler URL [/rest/images/uuid/XMLview] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)

    My servlet config is:

    and my method (which gets invoked and returns just fine) is:

    @RequestMapping( method=RequestMethod.GET, value=”/images/uuid/{id}” )
    public ModelAndView getEmployee(@PathVariable String id) throws VIOEException {
    Images i = Images.fetchByUuid( id );
    return new ModelAndView( “XMLview”, BindingResult.MODEL_KEY_PREFIX + “object”, i );
    }

    Any ideas?

    Thanks and Regards,

    Barry

  25. Adeel Shafqaton 28 Sep 2011 at 8:11 am

    very nice article

    Another good resource
    http://eiconsulting.blogspot.com/2011/09/restful-webservices.html

  26. Anonymouson 20 Dec 2011 at 7:21 am

    Good one::::::::::

  27. pavaon 20 Dec 2011 at 7:22 am

    goooood one::::::::::

  28. ganesh krishnanon 12 Mar 2012 at 3:40 am

    A very good article Tony.Keep up the good work.

  29. Taran Singhon 22 Mar 2012 at 12:11 pm

    Very simple and cleanly explained, I liked your gentleness for saying XStream choice was purely based on what you know/like…. as we have lot lot of these frameworks now.
    Thanks and best of luck

  30. Robert Morschelon 31 Jul 2012 at 9:06 am

    If you’ve wondered about how to document your Spring RESTful services then I suggest taking a look at RESTdoclet (recently open-sourced by IG Group). It also has a very nice working sample application that demonstrates some of the more sophisticated features like exception handling.

    More info at http://soaprobe.blogspot.co.uk/2012/07/rest-service-documentation-using.html .

    Robert

  31. Anonymouson 22 Aug 2012 at 9:28 am

    very good blogs,very helpful.