Archive

Posts Tagged ‘Rest Endpoint’

JSON/XML/RSS Rest Endpoints using Spring 3.1

May 13th, 2012 1 comment

Spring 3.0 introduced support for REST and this has got even better with Spring 3.1. In this post, I will use Spring 3.1 to create REST endpoints that will serve book information in JSON, XML and RSS formats.

To get started, add the following dependencies to your Spring based web application:

jackson-all-1.9.7.jar for generating JSON output
rome-1.0.jar for generating RSS/Atom feeds
JDOM 1.0 Jar a ROME project dependency

Maven users can get these jars by adding the following dependencies to their pom.xml:

		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-jaxrs</artifactId>
			<version>1.9.7</version>
		</dependency>
		<dependency>
			<groupId>rome</groupId>
			<artifactId>rome</artifactId>
			<version>1.0</version>
		</dependency>
	

Spring’s REST support is built on top of Spring MVC. So, we start out by creating a Spring MVC web controller as shown below:

package com.inflinx.blog.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.inflinx.blog.domain.Book;

@RequestMapping("/book")
@Controller
public class BookController {
	
	@RequestMapping(method = RequestMethod.GET)
	public String showBook(Model model) 
	{
		model.addAttribute("book", new Book("Practical Spring LDAP", "978-1475265453", "Balaji Varanasi"));
		
		return "book";
	}
	
}

In the above controller, we used the “/book” path with out the usual .html extension. This allows the controller to serve additional media type requests such as JSON and XML. On a GET request,
the showBook method gets invoked. The method’s implementation simply adds the book data to the model.

The Book class implementation is given below. Since we will be using the standard JAXB for creating XML versions of the data, the Book class is annotated with the @XMLRootElement JAXB annotation.

package com.inflinx.blog.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="book")
public class Book 
{
	private String name;
	private String isbn;
	private String author;
	
	public Book()
	{
		
	}
	
	public Book(String name, String isbn, String author)
	{
		this.name = name;
		this.isbn = isbn;
		this.author = author;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getIsbn() {
		return isbn;
	}
	public void setIsbn(String isbn) {
		this.isbn = isbn;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
}

The “book” view returned by the showCatalog method is implemented using the following book JSP page:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
	<head>
		<title>Home</title>
	</head>
	<body>
		
		${book.name} (${book.isbn}) - ${book.author} 

	</body>
</html>

Finally, the Spring’s web context configuration is shown below:

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="com.inflinx.blog.web.controller" />
	
</beans:beans>

Up to this point, we have simply created a standard Spring MVC based web application with one controller. When we invoke the controller using the web browser, the following view gets rendered:

Now, converting this controller to serve JSON/XML/RSS variations simply involves configuring a ContentNegotiatingViewResolver. The needed configuration is showing below:


<beans:bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
		<beans:property name="order" value="1" />
		<beans:property name="mediaTypes">
			<beans:map>
				<beans:entry key="json" value="application/json"/>
				<beans:entry key="xml" value="application/xml"/>
				<beans:entry key="rss" value="application/rss+xml"/>
			</beans:map>
		</beans:property>
		<beans:property name="defaultViews">  
    		<beans:list>  
    			<!-- Renders JSON View -->
      			<beans:bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />  
      			
      			<!-- Renders XML View -->
      			<beans:bean class="org.springframework.web.servlet.view.xml.MarshallingView">
					<beans:constructor-arg>
						<beans:bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
							<beans:property name="classesToBeBound">
								<beans:list>
									<beans:value>com.inflinx.blog.domain.Book</beans:value>
								</beans:list>
							</beans:property>
						</beans:bean>
					</beans:constructor-arg>
				</beans:bean>
				
				 <!-- Renders RSS View -->
				<beans:bean class="com.inflinx.blog.web.view.BookRssView" />
    		</beans:list>  
  		</beans:property>		
	</beans:bean>

The ContentNegotiatingViewResolver is a specialized implementation that resolves a view based on the request file extension or Accept header.
In the above configuration we have set the order property to 1 indicating that it must be positioned first in the chain. Using the mediaTypes property, we have provided the mapping from file extension to media types.
Finally, we have used the defaultViews to indicate the classes that needs to be used for creating the view. Upon receiving a request the above view resolver will use the file extension to determine the appropriate view
and delegates the view creation to it.

Out of the box, Spring does not provide an RSS view. So, we need to implement an RSS view specific to the domain object or project. Here is the BookRssView implementation:


package com.inflinx.blog.web.view;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.view.feed.AbstractRssFeedView;

import com.inflinx.blog.domain.Book;
import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Item;

public class BookRssView  extends AbstractRssFeedView
{
	@Override
	protected void buildFeedMetadata(Map model, Channel feed,
			HttpServletRequest request) {
		
		feed.setTitle("Book Data");
		feed.setDescription("This is an awesome feed about my book.");
		feed.setLink("blog.inflinx.com");
		
	}
	
	@Override
	protected List buildFeedItems(Map model, HttpServletRequest request, 
				HttpServletResponse response) throws Exception {
		
		// Get the book from the model
		Book book = (Book)model.get("book");
		
		// Create feed items
		List items = new ArrayList();
		Item item = new Item();
		item.setAuthor(book.getAuthor());
		item.setTitle(book.getName());
		item.setLink("http://inflinx.com/ldap");
		items.add(item);
		
		return items;
	}

}


The BookRssView extends Spring’s AbstractRssFeedView. In the buildFeedMetadata we create RSS metadata such as title, link and description. In the buildFeedItems we create the items that needs to be part of the RSS feed.

Now, when we hit the controller with a json extension we will get the JSON output as shown below:

JSON View

Similarly, the XML view is shown below:
XML View

Finally, the RSS view is below:
RSS View

Categories: Rest Tags: , , ,