Roo-based Jersey Apps on GAE

6 minute read Published:

This past weekend I put together an example of a Spring Roo-based Jersey application that can run on Google App Engine. All code in this post is derived from the example project at You should be able to get a project up and running by copy and pasting the snippets in this entry, or you can clone the project and follow along. This example uses Spring Roo 1.1.1, Jersey 1.5 and App Engine SDK 1.4.0. A basic understanding of the involved technologies is assumed.


The first step is to create your project. Create a directory for the project, fire up the Roo shell and then enter the commands below. This will both create a new project and configure it to use App Engine for persistence. Make sure to substitute an actual app id for your-appid if you plan to deploy this example.

project --topLevelPackage com.example.todo persistence setup --provider DATANUCLEUS --database GOOGLE_APP_ENGINE --applicationId your-appid


Once you’ve set up your project for GAE, you’ll need to add the dependencies for Jersey and JAXB. If adding them manually, you can refer to the dependencies section of the Jersey documentation. In either case, you’ll need to add the Jersey repository to your pom.xml. Repository for Maven default


Once you’ve added the Jersey repository, you can use these command to add the dependencies to your project.

dependency add --groupId com.sun.jersey --artifactId jersey-server --version 1.5 dependency add --groupId com.sun.jersey --artifactId jersey-json --version 1.5 dependency add --groupId com.sun.jersey --artifactId jersey-client --version 1.5 dependency add --groupId com.sun.jersey.contribs --artifactId jersey-spring --version 1.5

Unfortunately the jersey-spring artifact depends on Spring 2.5.x. Because Roo is based on Spring 3.0.x, you need to add some exclusions to prevent pulling in incompatible versions of Spring artifacts.

com.sun.jersey.contribs jersey-spring 1.5 org.springframework spring org.springframework spring-core org.springframework spring-web org.springframework spring-beans org.springframework spring-context


App Engine has issues with some versions of JAXB. I found 2.1.12 to work, while 2.1.13 and 2.2.x versions did not. This will hopefully change in the future. You can add a dependency on JAXB with the following command.

dependency add --groupId com.sun.xml.bind --artifactId jaxb-impl --version 2.1.12


If you’re adding jersey to a project that uses Roo’s web tier, you’ll already have the spring-web dependency in your project. If not, you’ll need to add that too.

dependency add --groupId org.springframework --artifactId spring-web --version ${spring.version}

You can specify an explicit version, but if you created your project with Roo, the spring.version build property should be set. Either way you’ll want to exclude commons-logging.

org.springframework spring-web ${spring.version} commons-logging commons-logging

Maven GAE Plugin

For some reason Roo uses a rather old version of the Maven GAE Plugin. The latest version at the time of this writing is 0.8.1. In addition to what Roo will have created for you, you’ll want to bind the start and stop goals if you plan on running integration tests. See the pom.xml in the example project for an example of how to do that.

net.kindleit maven-gae-plugin 0.8.1 ${gae.version} validate unpack


Next you’ll want to create an entity, which you can do with the commands below.

enum type --class ~.Status enum constant --name CREATED enum constant --name DONE entity --class ~.Todo --testAutomatically field string --fieldName description field enum --fieldName status --type ~.Status

In order to leverage Jersey’s JAXB serialization features, you’ll need to annotate your entity with @XmlRootElement. Set a default value for status while you’re here.

import javax.xml.bind.annotation.XmlRootElement; @RooJavaBean @RooToString @RooEntity @XmlRootElement public class Todo { @Enumerated private Status status = Status.CREATED; ...


Here’s a very simple resource for the entity we created earlier. In addition to the JAX-RS annotations, you also need to annotate the class with @Service, which makes the class eligible for dependency injection and other Spring services. This resource will support both XML and JSON.

package com.example.todo; import org.springframework.stereotype.Service; import*; import java.util.List; @Service @Consumes({"application/xml", "application/json"}) @Produces({"application/xml", "application/json"}) @Path("todo") public class TodoResource { @GET public List list() { return Todo.findAllTodoes(); } @GET @Path("{id}") public Todo show(@PathParam("id") Long id) { return Todo.findTodo(id); } @POST public Todo create(Todo todo) { todo.persist(); return todo; } @PUT public Todo update(Todo todo) { return todo.merge(); } @DELETE @Path("{id}") public void delete(@PathParam("id") Long id) { Todo.findTodo(id).remove(); } }

Final Configuration

At a minumum, you’ll need to have Spring’s OpenSessionInView and Jersey’s SpringServlet filters set up in your web.xml. As with the spring-web module dependency, you will have to create a web.xml in src/main/webapp/WEB-INF if you don’t already have one.

org.springframework.web.context.ContextLoaderListener contextConfigLocation classpath*:META-INF/spring/applicationContext*.xml Spring OpenEntityManagerInViewFilter Spring OpenEntityManagerInViewFilter /* Jersey Spring Web Application com.sun.jersey.spi.spring.container.servlet.SpringServlet Jersey Spring Web Application /*

You may also need to change the project’s packaging type to war.

com.example.todo todo war 0.1.0.BUILD-SNAPSHOT


You can now compile and run the application locally with mvn clean gae:run.

> mvn clean gae:run ... INFO: The server is running at http://localhost:8080/

The following curl commands can be used to interact with the running application.

# list curl -i -HAccept:application/json http://localhost:8080/todo # show curl -i -HAccept:application/json http://localhost:8080/todo/1 # create curl -i -HAccept:application/json -HContent-Type:application/json \ http://localhost:8080/todo -d '{"description":"walk the dog"}' # update curl -i -HAccept:application/json -HContent-Type:application/json \ http://localhost:8080/todo \ -d '{"description":"walk the dog","id":"1","status":"DONE","version":"1"}' \ -X PUT # delete curl -i http://localhost:8080/todo/1 -X DELETE

Once you’re happy with your application, you can upload it to App Engine. If you download the example project I created, you can build locally with mvn clean install -Dtodo-appid=<your-appid>. The local App Engine server will be used to run some basic integration tests during the build. After the app is built, you can deploy it with mvn gae:deploy. You will be prompted for your login information if you have not set up your your credentials in your settings.xml. Once deployed, you can run the included integration test against the live server with mvn failsafe:integration-test<your-appid> -Dgae.port=80. There is also a simple client you can use to write your own tests or experiment with.

Having some level of integration tests for any GAE apps you write is very important, as there are things that do not work consistently between the local development server and the real App Engine servers. Be aware that you can access the local development server console at http://localhost:8080/_ah/admin, which will let you browse the datastore amongst a few other things. Once deployed to the real App Engine, you’re best source of information is the application log. Be sure you’re looking at the correct version; there’s a drop-down menu in the upper left area of the screen that will let you choose the version of the logs you want to examine.