Friday, March 7, 2008

Jersey... Jetty and Maven style!

I recently created a webapp that due to time constraints, I implemented with plain old servlets which I am comfortable with. In reality, the project was a perfect candidate to implement in RESTful style. I had been loosely following the Jersey project, part of the larger java.net Metro project, so I decided to give Jersey a try.

"Jersey is the open source ... JAX-RS (JSR 311) Reference Implementation for building RESTful Web services. But, it is also more than the Reference Implementation. Jersey provides additional APIs and extension points (SPIs) so that developers may extend Jersey to suite their needs."


My only requirements were really around a quick turn-around dev setup. So I wanted to use maven and the jetty plugin to preview the results quickly.

Jersey is still only available as an early access preview (0.5-ea) , so some of the examples I found were "out of date", as the team is still refactoring the implementation.

So, first step: create a maven war project structure and configure the web.xml to look this this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>com.sun.ws.rest.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.ws.rest.config.property.resourceConfigClass</param-name>
<param-value>com.sun.ws.rest.api.core.PackagesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.ws.rest.config.property.packages</param-name>
<param-value>org.naiade.tutorials.jersey;com.gestalt.gci.rest.resources</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
The two key things here are:
  • use the ServletContainer servlet (not ServletAdapter)
  • use the pluggable PackagesResourceConfig parameter value. This allows Jersey to auto find all REST resources based on the package names. This is configured in the additional parameter value. Here we provide a couple of packages to look in, semicolon separated.
For the code, I used the ShoeService example I found here.
As I mentioned before, Jersey is still evolving so I ended up making two code changes to still be able to compile under 0.5-ea:
  • @HttpMethod() changed to @GET or @POST
  • @UriTemplate() changed to @Path()
The maven project looks like:

<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.shoe</groupId>
<artifactId>shoeservice</artifactId>
<version>1.0</version>
<name>Shoe Service REST</name>
<packaging>war</packaging>
<dependencies>
<!-- jersery.dev.java.net -->
<dependency>
<groupId>jersey</groupId>
<artifactId>jersey</artifactId>
<version>0.5-ea</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.8</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-j2ee_1.4_spec</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

To bring it all together, it's as simple as
mvn jetty:run
Open you browser and hit http://localhost:8080/shoeservice/shoe

Easy.

I really see Jersey taking off as it is a good project and easy to work with. If you are looking for a good Java solution to creating a RESTful accessible services, give it a try.

4 comments:

jlorenzen said...

Very nice. This is well needed. My team has on their backlog upgrading to the latest release. We are several versions behind.
One question though. Did you have to specify the maven2 repository for the jersey dependencies? If so could you include that in your example.

Jeff Black said...

The jersey and jsr311-api jars are available in the java.net maven repository. In you pom.xml, just add:

<repositories>
<repository>
<id>java.net</id>
<name>java.net Repository</name>
<url>http://download.java.net/maven/1/</url>
<layout>legacy</layout>
</repository>
</repositories>

codebeneath said...
This comment has been removed by a blog administrator.
Anonymous said...

Hi,

The Shoe example doesn't appear to work. The form returned by the .../show/new URI does not specify POST as the method. Even after adding this, it doesn't work for me - then I'm faced with the question.. why... and god knows how I dig through this stupid framework!

Too much magic.