X

Jersey and Spring

Guest Author

by Paul Sandoz

Jersey is an open-source, production-ready reference
implementation of JAX-RS, the Java API for RESTful
Web Services (JSR-311). JAX-RS is an annotation-driven API that makes it easy to build Java-based RESTful web
services that adhere to the REST architectural style. The JAX-RS API is standardized by the Java Community Process.
The JAX-RS API is currently at version 1.0 and Jersey is at version 1.0.2.

Jersey provides additional value beyond the JAX-RS API. It provides its own APIs that support

Atom's XML format
,

MIME MultiPart message format
,

JavaScript Object Notation (JSON)
,
Web Application Description Language (WADL),
as well as

Spring framework integration
. Jersey is shipped with GlassFish and is available from the GlassFish version 2 and version 3
update centers.

An earlier Tech Tip,
Implementing RESTful
Web Services in Java
, introduced RESTful Web Services, JAX-RS, and Jersey. It also showed how
you can write RESTful web services that conform to the JAX-RS specification. Other tips on Jersey-related topics described
how to
configure JSON for RESTful
web services in Jersey 1.0
and how to
consume RESTful web services
with the Jersey client API
.

In this tip, you will learn how to use Jersey's integrated support for
Spring, a framework for building and running enterprise
Java applications. You'll learn how to configure Spring with Jersey and use Jersey's Spring-related features.
The tip assumes that you are familiar with Spring concepts. If not, refer to the
Spring Tutorial.

Creating a Basic Web Application

To demonstrate Jersey's Spring-related features, you'll first create a simple web application, one that does not
use Spring and then change it to use Spring. Let's use the
Maven 2 software project management tool
to build the simple web application. If you're not familiar with Maven, see
Welcome to Maven and
Building
Web Applications with Maven 2
.

First, create a Maven 2 project by running the following Maven 2 archetype plugin in a command line:



   mvn archetype:generate -DarchetypeCatalog=http://download.java.net/maven/2




In response, Maven 2 will prompt you to choose an archetype, that is, a Maven 2 project template, from the archetypes
listed in the archetype catalog, archetype-catalog.xml, at URL http://download.java.net/maven/2:



   Choose archetype:
1: http://download.java.net/maven/2 -> jersey-quickstart-grizzly (Archetype for creating a RESTful web application with Jersey and Grizzly)
2: http://download.java.net/maven/2 -> jersey-quickstart-webapp (Archetype for creating a Jersey based RESTful web application WAR packaging)
Choose a number: (1/2):




Choose 2, jersey-quickstart-webapp. You will then be prompted for a group ID and an artifact ID. Enter
example.jersey.spring for the group ID and example-spring-jersey for the artifact ID.
Accept the default values for the other prompts.

After you confirm the inputs, Maven 2 creates a new subdirectory called example-spring-jersey, which contains
a template for the new Jersey-based web application. Figure 1 shows the expanded structure of the
example-spring-jersey directory.













Expanded Structure of the example-spring-jersey directory

Figure 1. Expanded Structure of the example-spring-jersey directory



Maven 2 also creates a Project Object Model (POM) file, pom.xml, which contains an XML representation of the
Maven project. You can find the pom.xml file in the example-spring-jersey directory.
If you navigate below the example-spring-jersey directory to
src/main/java/example/jersey/spring, you'll see a Java class named MyResource that
represents a resource used in the application. You'll also find a web.xml file for the web application
in the src/main/webapp/WEB-INF directory.

Let's build, deploy, and test the web application to see if it works. To build the application, go to the
example-spring-jersey directory and enter the following command:



   mvn clean install




In response, Maven 2 compiles the source code and creates an example-spring-jersey.war file
for the application.

To deploy the application, GlassFish V3 Prelude must be running. Start GlassFish V3 Prelude if it isn't already running.
To start GlassFish V3 Prelude, enter the following command:



   <GF_install_dir/bin>asadmin start-domain domain1




where <GF_install_dir/bin> is the directory where you installed GlassFish v3 Prelude.

Deploy the application to GlassFish v3 Prelude using the following command:



   asadmin deploy --force=true target/example-spring-jersey.war




Finally, you can verify that the deployed application runs by using the command line tool,
curl, as follows:



   curl -v http://localhost:8080/example-spring-jersey/webresources/myresource




In response, you should see the following output in the command window:



   \* About to connect() to localhost port 8080 (#0)
\* Trying 127.0.0.1... connected
\* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /example-spring-jersey/webresources/myresource HTTP/1.1
> User-Agent: curl/7.17.1 (i586-pc-mingw32msvc) libcurl/7.17.1 OpenSSL/0.9.7c zib/1.2.3
> Host: localhost:8080
> Accept: \*/\*
>< HTTP/1.1 200 OK< X-Powered-By: Servlet/2.5< Server: Sun Java System Application Server 9.1_02< Content-Type: text/plain< Transfer-Encoding: chunked< Date: Thu, 02 Apr 2009 22:18:29 GMT<
Hi there!\* Connection #0 to host localhost left intact
\* Closing connection #0




You can also verify the application by pointing your browser to the
URL http://localhost:8080/example-spring-jersey/webresources/myresource. You
should see the following text displayed on the page: Hi there!

Transforming the Web Application to Use Spring

Now let's change the web application to use Spring. To do that, you need to take the following actions:


Modify the pom.xml File: Recall that one of the files generated when you
created the Maven 2 project for the web application is a pom.xml file that
represents the Maven project. Replace the contents of the pom.xml file with
the content shown here.

The replacing code simplifies the Maven configuration to only use the required dependencies for this example.
Note especially the following code, which adds the Jersey Spring dependency, using the jersey-spring module:



   <dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
<version>${jersey-version}</version>
</dependency>





Create a Spring Application Context Configuration: The Spring application context configuration file
specifies an application's configuration for initialization by Spring. You need to create a Spring application context
configuration file for the web application. Create a file applicationContext.xml and put it in the
src/main/resources directory. The file should have the following content:



   <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">
<context:component-scan base-package="example.jersey.spring"/>
</beans>




This configuration directs Spring to use autowiring with Spring-based annotations and to scan for Spring-based resources
in the Java package example.spring.jersey. Autowiring is a feature in Spring that allows it to introspect
bean classes for dependencies so that you do not have to explicitly specify bean properties or constructor arguments.


Modify the web.xml File: Replace the contents of the web.xml file with
the content shown here.

The following code in the updated web.xml file declares the Spring application context configuration,
created earlier as a servlet context parameter:



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




The updated content also declares two listeners. The first configures Spring and the second configures
Spring for use with the request scope for Spring beans.



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




Then, the file declares the Jersey Spring servlet, which supports the Jersey integration with Spring.



   <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
</servlet>





Modify the Root Resource Class: Modify the MyResource.java file in the
src/main/java/example/jersey/spring directory with the following content:



   package example.jersey.spring;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
// The Java class will be hosted at the URI path "/myresource"
@Path("/myresource")
@Component
@Scope("request")
public class MyResource {
// The Java method will process HTTP GET requests
@GET
// The Java method will produce content identified by the MIME Media
// type "text/plain"
@Produces("text/plain")
public String getIt() {
return "Hi there!";
}
}




The @Component annotation declares that the class is a Spring bean class.
The @Scope("request") annotation declares that instances of this class will be instantiated
within the scope of the HTTP request. This highlights a difference between the default scopes for JAX-RS or Jersey
and Spring. The default scope for JAX-RS is per request. By comparison, the default scope for Spring is a singleton,
that is, one instance per web application. See Supported Scopes for more information about the
scopes that Jersey supports.

The MyResource root resource class is functionally equivalent to the root resource class that you originally
created, but it's now Spring-enabled.

Verify that the Spring-enabled web application deploys and executes by entering the following commands in a command line:


   mvn clean install
asadmin deploy --force=true target/example-spring-jersey.war
curl -v http://localhost:8080/example-spring-jersey/webresources/myresource




After the Spring-enabled web application is successfully deployed, you should see output
similar to the following in the server.log
(<GF_install_dir>/glassfish/domains/domain1/logs/server.txt):



   [PWC1412: WebModule[/example-spring-jersey] ServletContext.log():Initializing Spring root WebApplicationContext|#]
[INFO| Root WebApplicationContext: initialization started|]
[INFO| Refreshing org.springframework.web.context.support.XmlWebApplicationContext@53ecec: display name [Root WebApplicationContext]; startup date [Mon Apr 06 14:37:02 PDT 2009]; root of context hierarchy|#]
[INFO| Loading XML bean definitions from class path resource [applicationContext.xml]|#]
[INFO| Bean factory for application context [org.springframework.web.context.support.XmlWebApplicationContext@53ecec]: org.springframework.beans.factory.support.DefaultListableBeanFactory@c0267a|#]
[INFO| Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c0267a: defining beans [myResource,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor]; root of factory hierarchy|#]
[INFO| Root WebApplicationContext: initialization completed in 891 ms|#]
[INFO| Loading application example-spring-jersey at /example-spring-jersey|#]
[INFO| Deployment of example-spring-jersey done is 4500 ms|#]
[INFO| Registering Spring bean, myResource, of type example.jersey.spring.MyResource as a root resource class|#]




Notice the final line that begins "Registering Spring bean". This is output from Jersey. Jersey knows that the
class MyResource is a root resource class and also a Spring bean class. No Jersey-specific configuration was
required to register root resource classes, as was the case in the web.xml for the original version of the
web application.

Because Spring is used to register Spring beans, in this case using autowiring, Jersey leverages Spring to perform
registration rather that requiring duplicate registration. It is possible to intermix Spring-managed and Jersey-managed
root resource classes by using Jersey's registration mechanism. It does not matter if both Spring and Jersey find the same
class -- only one reference to the class will be managed appropriately.


Supported Scopes

Jersey supports the following Spring scopes:

  • Request. Scopes a single Spring bean definition to the lifecycle of a single HTTP request, that is, each HTTP request has
    its own instance of a Spring bean created from a single Spring bean definition. This scope requires that you declare the Spring
    RequestContextListener servlet context in the web.xml file for the web application.
  • Singleton. Scopes a single Spring bean definition to a single object instance per web application.
  • Prototype. Scopes a single Spring bean definition to multiple object instances. A new Spring bean instance is created for
    each request for that specific bean.

You can inject Jersey artifacts into fields of Spring bean instances according to the scoping rules. If the scope is
prototype, then the scoping rules for request apply. If Jersey does not recognize the scope, then it assumes a scope
of singleton for the purpose of injection.

For example, you can modify the MyResource class in the Spring-enabled Web application to include an
@QueryParam for injection. Here is what the modified class looks like:



   package example.jersey.spring;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
// The Java class will be hosted at the URI path "/myresource"
@Path("/myresource")
@Component
@Scope("request")
public class MyResource {
@QueryParam("x") String x;
// The Java method will process HTTP GET requests
@GET
// The Java method will produce content identified by the MIME Media
// type "text/plain"
@Produces("text/plain")
public String getIt() {
return "Hi there! " + x;
}
}




In response, Jersey should inject the information into the Spring bean in request scope, that is, per request.
To test that, you can redeploy and execute the updated application by entering the following commands in a command line
window:



   mvn clean install
asadmin deploy --force=true target/example-spring-jersey.war
curl -v http://localhost:8080/example-spring-jersey/webresources/myresource?x=curl




The application should return "Hi there! curl" in the output. If it does, this verifies that Jersey can correctly
inject information into the Spring bean per request.

Summary

This tip showed you how to use some of Jersey's Spring-related features. But there are other useful elements to
Jersey's support for Spring. Some of the these are:

  • You can take advantage of the JAX-RS support for hierarchical URI path matching to further match a URI path that
    was not already matched by a root resource. This means that you can include a subresource locator method in a resource
    to return an instance of a newly created Spring bean class. You use the Jersey ResourceContext class
    to obtain the instance.

  • You can inject Spring beans into JAX-RS-based methods. You do this with the Jersey @Inject annotation.
  • You can use Jersey Spring-based Aspect-Oriented Programming (AOP).
  • You can have Spring instantiate a resource class, but have Jersey manage the resource class's lifecycle.

Further Reading

For more information on Jersey and Spring, see the following resources:


About the Author

Paul Sandoz is the co-spec lead and implementation lead for JSR 311: Java API for RESTful Web Services. He has participated
in the W3C, ISO, and ITU-T standards organizations and contributed various performance-related technologies and improvements
to the GlassFish web services stack, particularly in standardization, implementation, integration, and interoperability of
Fast Infoset.



2009 JavaOne Conference, June 2-5, San Francisco \*\* Register Now\*\*

Stay on top of everything new and different, both inside and around Java technology. Register by April 22, 2009,
and save $200 off a Conference Pass or Conference Plus Pass. Register now at
http://java.sun.com/javaone.

Join the discussion

Comments ( 18 )
  • Paul Sandoz Tuesday, April 14, 2009

    For developers wishing to avoid the dreaded command line it is possible to utilize NetBeans 6.5 with the maven plugin to deploy the project to Glassfish V3 Prelude. And of course, as stated, the URLs can be accessed using the browser instead of curl.


  • redhacker Wednesday, April 15, 2009

    Thanks, paul,It is a good article!


  • guest Tuesday, April 28, 2009

    It is a good article. Thanks!


  • guest Wednesday, April 29, 2009

    Est-il possible d'avoir la traduction française ? Thanks


  • Paul Sandoz Thursday, April 30, 2009

    Mon français n'est pas assez bon. J'ai demandé à quelqu'un qui pourrait le savoir. Mais, peut-être que quelqu'un peut offrir ses services?


  • Em Thursday, June 4, 2009

    Is it possible to post the pom.xml for maven?


  • Paul Sandoz Friday, June 5, 2009
  • Em Monday, June 8, 2009

    thx Paul.

    Can I return a ModelAndView - Object instead of a String?

    In my example I get this error: A message body writer for Java type, class org.springframework.web.servlet.ModelAndView, and MIME media type, text/html, was not found. The InternalResourceViewResolver is configured.


  • Paul Sandoz Thursday, June 11, 2009

    @Em, apologies for the late reply.

    Integration with Spring's model/view is not currently implemented.

    You will need to add your own MessageBodyWriter to support the processing of the ModelAndView instance.

    I recommend we continue discussions on:

    mailto:users@jersey.dev.java.net

    as it is easier to have a conversation.

    Paul.


  • David Friday, July 24, 2009

    Thanks Paul,

    I implemented your implementation and it worked. The only problem is that it wouldn't integrate with Spring's JPA which doesn't lead to a very useful REST application. I'm begining to think that although Annotations are a cool idea when it comes to debugging they are a nightmare.

    Funny its hard to find an exemplar of Spring JPA with Jeresy. I suppose it will have to be wall to wall Spring implementations in the end with Spring 3.0. I would however prefer a bit more diversity.

    David


  • Paul Sandoz Monday, July 27, 2009

    I do not know anything about Spring JPA. Can you describe what did not work with Spring JPA? perhaps you can email:

    mailto:users@jersey.dev.java.net

    then i and others can discuss.

    Re: annotations. Good error reporting is a must, we have tried to do that in Jersey so it reports all errors about resource classes, rather than one at a time. Tooling can also help a lot. IMHO if i were to choose between an XML document or annotations i would choose the latter. I cannot imagine the PITA it would be to use an XML document rather than annotations for JAX-RS.

    Paul.


  • Matthew Sowders Friday, September 25, 2009

    Thanks very much for the quick tutorial. FYI I had to modify my web.xml to point to the jersey/spring servlet like so

    <servlet>

    <servlet-name>Jersey Spring</servlet-name>

    <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>

    </servlet>

    <servlet-mapping>

    <servlet-name>Jersey Spring</servlet-name>

    <url-pattern>/resources/\*</url-pattern>

    </servlet-mapping>


  • Edward Ort Tuesday, September 29, 2009

    Yes, this is covered in the section "Modify the web.xml File".


  • Roger Nilsson Tuesday, October 27, 2009

    Thank you for this article.

    Works fine when using spring 2.5.6 in the project. But there seems to be a problem when trying to run with spring 3.0.0.RC1.

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/xxx/dao/impl/JpaAuditDAOTest-context.xml]: Initialization of bean failed; nested exception is java.lang.reflect.MalformedParameterizedTypeException


  • Davide Monday, May 31, 2010

    Thank you to this post!

    I was making me crazy, trying to find solution of spring context propagations!!

    RESPECT!

    Davide


  • Arvind Katoch Wednesday, September 1, 2010

    It's really great article.

    Thanks.


  • skay Thursday, September 2, 2010

    I saw different posts about problems with Spring, and I encounter same issue as Roger Nilson.

    Actually, Jersey-spring (I used 1.3) gathers dependencies to spring 2.5.

    If you are using Maven, add <exclusions> clause to your pom.xml for the jersey-spring <dependency>. Double-check in Eclipse imports.

    (Currently), it runs fine for me with spring 3.1.

    BR.


  • Meghana Wednesday, October 20, 2010

    Thank you!!


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha