Jersey REST 0.7, now with Spring support

The Jersey REST API 0.7 is out and now includes support for the Spring framework. Peter Liu has written a nice example that uses NetBeans 6.1 to create a web application that contains a Spring-aware servlet, a singleton resource, and a request resource. His example is derived from a blog post by Paul Sandoz showing how to manually integrate Spring and Jersey (and predating REST 0.7).

Note that in REST 0.8, Spring support will be enhanced so that the user does not have to create a Spring-aware servlet.

This is Peter's example. It requires NetBeans IDE Web and Java EE distribution 6.1 and REST plugin 0.7.

  1. Create a Web Application project and name it SpringRestWebApp. On the Frameworks page of the project creation wizard, select Spring Web MVC 2.5.
  2. Right-click the SpringRestWebApp node and choose New > RESTful Web Services from Patterns. Select the Singleton pattern and name the resource Singleton (class name will then be SingletonResource). Create the test.servlet package to contain the resource.
  3. Replace the code in SingletonResource with the following. Right-click in the code and select Fix Imports after replacing the code.
    @Path("singleton")
    @Singleton
    public class SingletonResource {
        
        private String name;
        
        private int uses = 0;
        
        private synchronized int getCount() {
            return ++uses;
        }
        
        public SingletonResource() {
            name = "unset";
        }
    
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
        
        @GET
        @ProduceMime("text/plain")
        public String getDescription() {
            return "Name: " + getName() + ", Uses: " + Integer.toString(getCount());
        }
    }
  4. Create another RESTful Web Service using the Singleton pattern. Name the resource PerRequest and create it in the same test.servlet package.
  5. Replace the code in PerRequestResource with the following. Right-click in the code and select Fix Imports when you are done.
    @Path("request")
    public class PerRequestResource {
        
        private String name;
        
        private int uses = 0;
        
        private synchronized int getCount() {
            return ++uses;
        }
        
        public PerRequestResource() {
            name = "unset";
        }
    
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
        
        @GET
        @ProduceMime("text/plain")
        public String getDescription() {
            return "Name: " + getName() + ", Uses: " + Integer.toString(getCount());
        }
    }
  6. Right-click the SpringRestWebApp node and choose New > Servlet. Name the servlet SpringServlet and create it in the test.servlet package.
  7. Replace the code in SpringServlet with the following. Right-click in the code and select Fix Imports when done.
    public class SpringServlet extends ServletContainer {
        
        private static class SpringComponentProvider implements ComponentProvider {
            private ApplicationContext springContext;
    
            SpringComponentProvider(ApplicationContext springContext) {
                this.springContext = springContext;
            }
            
            private String getBeanName(Class c) {
                String names[] = springContext.getBeanNamesForType(c);
                if (names.length == 0) {
                    return null;
                } else if (names.length > 1) {
                    throw new RuntimeException("Multiple configured beans for " 
                            + c.getName());
                }
                return names[0];            
            }
            
            public Object getInstance(Scope scope, Class c) 
                    throws InstantiationException, IllegalAccessException {            
                String beanName = getBeanName(c);
                if (beanName == null) return null;
                
                if (scope == Scope.WebApplication && 
                        springContext.isSingleton(beanName)) { 
                    return springContext.getBean(beanName, c);
                } else if (scope == Scope.ApplicationDefined &&
                        springContext.isPrototype(beanName) &&
                        !springContext.isSingleton(beanName)) {
                    return springContext.getBean(beanName, c);
                } else {
                    return null;
                }
            }
    
            public Object getInstance(Scope scope, Constructor contructor, 
                    Object[] parameters) 
                    throws InstantiationException, IllegalArgumentException, 
                    IllegalAccessException, InvocationTargetException {
                return null;
            }
    
            public Object getInjectableInstance(Object instance) {
               return instance;
            }
            
            public void inject(Object instance) {
            }        
        };
        
        @Override
        protected void initiate(ResourceConfig rc, WebApplication wa) {
            ApplicationContext springContext = WebApplicationContextUtils.
                    getRequiredWebApplicationContext(getServletContext());
            
            wa.initiate(rc, new SpringComponentProvider(springContext));
        }        
    }

    Paul Sandoz writes "Notice that SpringServlet extends ServletContainer and the initiate method is overridden. This method creates an ApplicationContext and then initiates the WebApplication by passing in an instance of the static inner class SpringComponentProvider. This class implements ComponentProvider and the getInstance method will attempt to obtain a Spring bean that is present and matches the requested scope, if so then the bean instance is returned otherwise null is returned. (Note that the getInstance method with a Constructor type parameter is not implemented, this is because we have not determined how to support constructors with Spring beans)."

  8. Open the project's web.xml file. Replace com.sun.ws.rest.impl.container.servlet.ServletAdaptor with test.servlet.SpringServlet.
  9. Add the following to the project's applicationContext.xml file, to initialize the resources:
    <bean id="bean1" scope="singleton" class="test.servlet.SingletonResource">
         <property name="name" value="Mr. Singleton Bean"/>
    </bean>
    <bean id="bean2" scope="prototype" class="test.servlet.PerRequestResource">
         <property name="name" value="Mr. PerRequest Bean"/>
    </bean>
  10. Right-click the project node and select Test RESTful Web Services.
When you test the Singleton path, the service returns the Mr. Singleton Bean property and the Uses value increments for every request. When you test the PerRequest path, the service returns the Mr. PerRequest Bean property and the Uses value does not increment.
Comments:

Hi Jeffrey,

I think that naming your module just "REST" is quite confusing... As you know, REST is the acronym coined by Roy T. Fielding in his thesis [1] and not a product name.

Best regards,
Jerome

[1] http://roy.gbiv.com/pubs/dissertation/rest_arch_style.htm

Posted by Jerome Louvel on June 13, 2008 at 05:18 PM CEST #

In Jersey REST 0.8, the Spring-aware servlet is incorporated in the Jersey libraries. On NetBeans 6.5, you can simply create a Java Web application with the Spring framework and create a RESTful web service as usual within that application.

Posted by Jeff Rubinoff on August 25, 2008 at 11:00 AM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

I'm a technical writer for NetBeans, covering web service support.

Search

Categories
Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today