REST support
Introduction The goal of Spring's REST support is to make the development of RESTful Web services and applications easier. Client-side access to RESTful resources is greatly simplified using Spring RestTemplate. RestTemplate follows in the footsteps of other template classes in Spring such as JdbcTemplate and JmsTemplate. Instead of dealing with a verbose lower level API such as Apache Commons HttpClient to create RESTful request, RestTemplate provides one liner methods that are purpose built for RESTful programming. On the server-side, Spring's REST support is based upon Spring's existing annotation based MVC framework. (For those interested in the rational for that decision, and for not implementing JAX-RS, read Arjen Poutsma's SpringSource TeamBlog entry.) With little effort, you can marshall data out of a RESTful request using @RequestMapping and @PathVariable annotations and return different views as determined by the request's Context-Type header. In this chapter we describe all the features of Spring's REST support. It is divided into two main chapters, one for the server-side and one for the client-side. For those new to Spring's MVC framework, you may want to read through the reference documentation on annotation-based controller configuration to understand the general programming model.
Views Several views were added in Spring 3 to help support creating RESTful services. They are: AbstractAtomFeedView - returns an Atom feed AbstractRssFeedView - returns a RSS feed MarshallingView - returns an XML representation using Spring's Object to XML mapping (OXM) functionality Available separately is the JacksonJsonView included as part of the Spring JavaScript project.
Feed Views Both AbstractAtomFeedView and AbstractRssFeedView inherit from the base class AbstractFeedView and are used to provide Atom and RSS Feed views respectfully. They are based on java.net's ROME project and are located in the package org.springframework.web.servlet.view.feed. AbstractAtomFeedView requires you to implement the buildFeedEntries method and optionally override the buildFeedMetadata method (the default implementation is empty), as shown below public class SampleContentAtomView extends AbstractAtomFeedView { @Override protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) { // implementation omitted } @Override protected List<Entry> buildFeedEntries(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // implementation omitted } } Similar requirements apply for implementing AbstractRssFeedView, as shown below public class SampleContentAtomView extends AbstractRssFeedView { @Override protected void buildFeedMetadata(Map<String, Object> model, Channel feed, HttpServletRequest request) { // implementation omitted } @Override protected List<Item> buildFeedItems(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // implementation omitted } } The buildFeedItems and buildFeedEntires pass in the HTTP request in case you need to access the Locale. The HTTP response is passed in only for the setting of cookies or other HTTP headers. The feed will automatically be written to the response object after the method returns. For an example of creating a Atom view please refer to Alef Arendsen's SpringSource TeamBlog entry.
XML Marshalling View The MarhsallingView uses a XML Marshaller defined in the org.springframework.oxm package to render the response content as XML. The object to be marshalled can be set explicitly using MarhsallingView's modelKey bean property. Alternatively, the view will iterate over all model properties marhsall only those types that are supported by the Marshaller. For more information on the functionality in the org.springframework.oxm package refer to the chapter Marshalling XML using O/X Mappers.
HTTP Method Conversion A key principle of REST is the use of the Uniform Interface. This means that all resources (URLs) can be manipulated using the same four HTTP methods: GET, PUT, POST, and DELETE. For each methods, the HTTP specification defines the exact semantics. For instance, a GET should always be a safe operation, meaning that is has no side effects, and a PUT or DELETE should be idempotent, meaning that you can repeat these operations over and over again, but the end result should be the same. While HTTP defines these four methods, HTML only supports two: GET and POST. Fortunately, there are two possible workarounds: you can either use JavaScript to do your PUT or DELETE, or simply do a POST with the 'real' method as an additional parameter (modeled as a hidden input field in an HTML form). This latter trick is what Spring's HiddenHttpMethodFilter does. This filter is a plain Servlet Filter and therefore it can be used in combination with any web framework (not just Spring MVC). Simply add this filter to your web.xml, and a POST with a hidden _method parameter will be converted into the corresponding HTTP method request.
Supporting Spring form tags To support HTTP method conversion the Spring MVC form tag was updated to support setting the HTTP method. For example, the following snippet taken from the updated Petclinic sample <form:form method="delete"> <p class="submit"><input type="submit" value="Delete Pet"/></p> </form:form> This will actually perform an HTTP POST, with the 'real' DELETE method hidden behind a request parameter, to be picked up by the HiddenHttpMethodFilter. The corresponding @Controller method is shown below @RequestMapping(method = RequestMethod.DELETE) public String deletePet(@PathVariable int ownerId, @PathVariable int petId) { this.clinic.deletePet(petId); return "redirect:/owners/" + ownerId; }
ETag support An ETag (entity tag) is an HTTP response header returned by an HTTP/1.1 compliant web server used to determine change in content at a given URL. It can be considered to be the more sophisticated successor to the Last-Modified header. When a server returns a representation with an ETag header, the client can use this header in subsequent GETs, in an If-None-Match header. If the content has not changed, the server will return 304: Not Modified. Support for ETags is provided by the servlet filter ShallowEtagHeaderFilter. Since it is a plain Servlet Filter, and thus can be used in combination with any web framework. The ShallowEtagHeaderFilter filter creates so-called shallow ETags (as opposed to deep ETags, more about that later). The way it works is quite simple: the filter simply caches the content of the rendered JSP (or other content), generates an MD5 hash over that, and returns that as an ETag header in the response. The next time a client sends a request for the same resource, it uses that hash as the If-None-Match value. The filter notices this, renders the view again, and compares the two hashes. If they are equal, a 304 is returned. It is important to note that this filter will not save processing power, as the view is still rendered. The only thing it saves is bandwidth, as the rendered response is not sent back over the wire. Deep ETags are a bit more complicated. In this case, the ETag is based on the underlying domain objects, RDMBS tables, etc. Using this approach, no content is generated unless the underlying data has changed. Unfortunately, implementing this approach in a generic way is much more difficult than shallow ETags. Spring may provide support for deep ETags in a later release by relying on JPA's @Version annotation, or an AspectJ aspect.
Exception Handling The @ExceptionHandler method annotation is used within a controller to specify which method will be invoked when an exception of a specific type is thrown during the execution of controller methods. For example @Controller public class SimpleController { // other controller method omitted @ExceptionHandler(IOException.class) public String handleIOException(IOException ex, HttpServletRequest request) { return ClassUtils.getShortName(ex.getClass()); } } will invoke the 'handlerIOException' method when a java.io.IOException is thrown. The @ExceptionHandler value can be set to an array of Exception types. If an exception is thrown matches one of the types in the list, then the method annotated with the matching @ExceptionHandler will be invoked. If the annotation value is not set then the exception types listed as method arguments are used. Much like standard controller methods annotated with a @RequestMapping annotation, the method arguments and return values of @ExceptionHandler methods are very flexible. For example, the HttpServletRequest can be accessed in Servlet environments and the PortletRequest in Portlet environments. The return type can be a String, which is interpreted as a view name or a ModelAndView object. Please refer to the API documentation for more details.