Just REST, it’s Easy With Spring and Jersey


In one of the products that we are working on, there is a need to expose the API as REST so that it can be consumed by the developer community and foster innovation. I did a few prototypes for the combination of dependency injection and REST with Restlet, Guice, Jersey and Spring and finally settled with Jersey and Spring primarily due to the easy configuration and tooling available around the two. Let us see how to easily build a REST enabled service with Jersey and Spring.

First, let us quickly create a simple webapp using mvn archetype:generate, if you are using maven 3 then you would see a huge number of options. Pick up 104 😉 ( at least this is the number for mvn 3.0.2)

104: remote -> maven-archetype-webapp (An archetype which contains a sample Maven Webapp project.)

Ok, once we have the web app, then we need to add the relevant dependencies to the pom.xml. These are the ones that I added,

<repositories>
		<repository>
			<id>maven2-repository.dev.java.net</id>
			<name>Java.net Repository for Maven</name>
			<url>http://download.java.net/maven/2/</url>
			<layout>default</layout>
		</repository>
		<repository>
			<id>maven-repository.dev.java.net</id>
			<name>Java.net Maven 1 Repository (legacy)</name>
			<url>http://download.java.net/maven/1</url>
			<layout>legacy</layout>
		</repository>
	</repositories>
	
	
	<!-- Shared version number properties -->
	<properties>
		<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core</artifactId>
				<version>${org.springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-beans</artifactId>
				<version>${org.springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-web</artifactId>
				<version>${org.springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context</artifactId>
				<version>${org.springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring</artifactId>
				<version>${org.springframework.version}</version>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
		<dependency>
			<groupId>com.sun.jersey</groupId>
			<artifactId>jersey-server</artifactId>
			<version>1.5</version>
		</dependency>
		<dependency>
			<groupId>com.sun.jersey</groupId>
			<artifactId>jersey-json</artifactId>
			<version>1.5</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.8.2</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.sun.grizzly</groupId>
			<artifactId>grizzly-servlet-webserver</artifactId>
			<version>1.9.8</version>
		</dependency>
		<dependency>
			<groupId>com.sun.jersey</groupId>
			<artifactId>jersey-client</artifactId>
			<version>1.5</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.sun.jersey.contribs</groupId>
			<artifactId>jersey-spring</artifactId>
			<version>1.2</version>
			<exclusions>
				<exclusion>
					<groupId>org.springframework</groupId>
					<artifactId>spring</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<finalName>justrest</finalName>
		<plugins>
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>maven-jetty-plugin</artifactId>
				<version>6.1.17</version>
			</plugin>

		</plugins>
	</build>

Notice, that we need to include some repositories from java.net. Also, notice that we have a dependency on jersey-spring. As of now, jersey-spring depends on the Spring 2.5.6 framework, hence we are excluding it so that we can continue to use 3.0.5.RELEASE without getting into any conflicts

<dependency>
			<groupId>com.sun.jersey.contribs</groupId>
			<artifactId>jersey-spring</artifactId>
			<version>1.2</version>
			<exclusions>
				<exclusion>
					<groupId>org.springframework</groupId>
					<artifactId>spring</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

Now, let us look at the changes that we would have to make in web.xml. The most significant portion of the web.xml is the servlet mapping for the jersey spring servlet which looks like this

<servlet>
		<servlet-name>REST</servlet-name>
		<servlet-class>
			com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
		<init-param>
			<param-name>com.sun.jersey.config.property.packages</param-name>
			<param-value>com.inphina.sample</param-value>
		</init-param>
		<init-param>
			<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
			<param-value>true</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<!-- Map /rest/* to Jersey -->
	<servlet-mapping>
		<servlet-name>REST</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>

Next, we also include the standard listeners for Spring, so that it can create the beans, which are the following

<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
	</listener>

All right, so far so good. It seems that we have all the infrastructure for REST in place. Now, assume that you have a service with the following definition which you want to expose as REST

package com.inphina.sample;

public interface SpringService {

	public void helloMe();

}

And, the implementation looks like this


package com.inphina.sample;

public class SpringServiceImpl implements SpringService {

	public void helloMe() {
		System.out.println("The spring service is being invoked");

	}

}

Let us put this as a bean in the applicationContext.xml


<?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"
	xsi:schemaLocation="
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
	<bean id="springService" class="com.inphina.sample.SpringServiceImpl"> </bean>
</beans>

If you do a mvn jetty:run at this stage then may be it is all good (if you have been following the example closely) or you might get the following message


SEVERE: Exception occurred when intialization
com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.
	at com.sun.jersey.server.impl.application.RootResourceUriRules.(RootResourceUriRules.java:103)
	at com.sun.jersey.server.impl.application.WebApplicationImpl._initiate(WebApplicationImpl.java:1184)
	at com.sun.jersey.server.impl.application.WebApplicationImpl.access$600(WebApplicationImpl.java:159)
	at com.sun.jersey.server.impl.application.WebApplicationImpl$12.f(WebApplicationImpl.java:700)
	at com.sun.jersey.server.impl.application.WebApplicationImpl$12.f(WebApplicationImpl.java:697)
	at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:193)

If you get the above error, then it means that you have not pointed the servlet property

<init-param>
			<param-name>com.sun.jersey.config.property.packages</param-name>
			<param-value>com.inphina.sample</param-value>
		</init-param>

to the right location. The right location is the one which has a jersey based REST class. Let us write the root resource now

The class looks like this


package com.inphina.sample;

import java.util.logging.Logger;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import com.sun.jersey.spi.inject.Inject;

@Path("/helloworld")
public class HelloWorldResource {

	@Inject
	private SpringService springService;

	private final Logger LOGGER = Logger.getLogger(HelloWorldResource.class.getName());

	@GET
	@Produces("application/json")
	public Person getSomeMessage() {
		springService.helloMe();
		return new Person("Vikas Hazrati", 36, "vhazrati@inphina.com");
	}

	@PUT
	@Consumes()
	public void setNewText(String newText) {
		LOGGER.info("do something interesting |" + newText + "|");
	}
}

A few things here. Look at the @Path annotation, this is the rest path through which we would be able to call the REST service.

The @GET annotation shows the method which would be invoked for a GET call. The @Produces(“application/json”) annotation shows that the returned value would be in JSON format so that clients can consume it as a JSON object.

If you notice that we have included the following dependency in our pom.xml

<dependency>
			<groupId>com.sun.jersey</groupId>
			<artifactId>jersey-json</artifactId>
			<version>1.5</version>
		</dependency>

The @Inject annotation is used to inject the SpringService into the REST root resource.

So that is it, we are good. Let us give it a test run and see how it works.

Execute mvn jetty:run and access the URL at the following location

http://localhost:8080/justrest/rest/helloworld

we get the response back as a JSON object

{“name”:”Vikas Hazrati”,”email”:”vhazrati@inphina.com”,”age”:36}

and on the console we would see that our spring service is being called


28 Feb, 2011 11:12:32 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.5 01/14/2011 12:36 PM'
2011-02-28 23:12:33.464::INFO:  Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
The spring service is being invoked

Entire source code for this project is present here.

About Vikas Hazrati

Vikas is the Founding Partner @ Knoldus which is a group of software industry veterans who have joined hands to add value to the art of software development. Knoldus does niche Reactive and Big Data product development on Scala, Spark and Functional Java. Knoldus has a strong focus on software craftsmanship which ensures high-quality software development. It partners with the best in the industry like Lightbend (Scala Ecosystem), Databricks (Spark Ecosystem), Confluent (Kafka) and Datastax (Cassandra). To know more, send a mail to hello@knoldus.com or visit www.knoldus.com
This entry was posted in Java and tagged , , , . Bookmark the permalink.

4 Responses to Just REST, it’s Easy With Spring and Jersey

  1. Why not just use Spring MVC’s REST support?

    • Not sure if I can answer this one with conviction 🙂 I have not tried the Spring REST support yet. That is certainly worth a try and I would link my thoughts soon …

  2. Pingback: Inphina Thoughts

  3. Pingback: Testing Jersey Based REST Services with Grizzly « Inphina Thoughts

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s