users@jersey.java.net

Re: [Jersey] Integrating Jersey and Spring

From: Ronak Patel <ronak2121_at_yahoo.com>
Date: Tue, 19 Jan 2010 16:51:28 -0800 (PST)

Hi,

On a similar note,

I was wondering if JAX-RS Jersey is updated to use Spring Framework 3.0 now. If not, any clue as to when that support will be available?

Thanks!

Ronak Patel



________________________________
From: Brad Lee <s.brad.lee_at_gmail.com>
To: users_at_jersey.dev.java.net
Sent: Tue, January 19, 2010 12:28:20 PM
Subject: Re: [Jersey] Integrating Jersey and Spring

Hi Mahesh. Sorry I am late to reply here, this email never responded
directly to me. Anyway, on this email you will find the
JerseySpringController that very simply forwards Spring requests to
Jersey.

I don't have any examples of interceptors extending ContainerFilters
and Jersey Resource filters, but I don't honestly think that it would
be that hard to implement. If I ever have a need for one, then I will
post back when I write it.

Right now, I'm not bothering with annotations, although I would imagine
you could configure it using annotations. The properties file above is
what I use to inject the Properties instance variable on the
JerseController class.

Also, since Struts2 is YASF(yet another servlet framework), I would
think it very easy to forward requests it receives into Jersey.

package org.springframework.web.servlet.jersey;

import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;

import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.spi.container.WebApplication;
import com.sun.jersey.spi.container.servlet.ServletContainer;
import com.sun.jersey.spi.container.servlet.WebConfig;
import com.sun.jersey.spi.spring.container.SpringComponentProviderFactory;

public class JerseyController
extends ServletContainer
implements Controller, ServletContextAware, InitializingBean, ApplicationContextAware {
    //==========================================================================
    // Private Static Variables
    //==========================================================================
    private static final Logger logger =
        LoggerFactory.getLogger(JerseyController.class);
    //==========================================================================
    // SpringServlet methods are private instead of protected,
    // so I have to redo their servlet extension of ServletContainer...
    //==========================================================================
    @Override
    protected void initiate(ResourceConfig rc, WebApplication wa) {
        try {
            wa.initiate(rc, new SpringComponentProviderFactory(rc, getContext()));
        } catch (RuntimeException e) {
            logger.error("Exception occurred during initializing "+SpringComponentProviderFactory.class.getName()+"!", e);
            throw e;
        }
    }
    protected ConfigurableApplicationContext getContext() {
        final ConfigurableApplicationContext springContext =
                (ConfigurableApplicationContext) this.getApplicationContext();
        return springContext;
    }
    
    //==========================================================================
    // Instance Variables
    //==========================================================================
    private ServletContext springServletContext;
    private Properties jerseyConfiguration;
    private ApplicationContext applicationContext;
    //==========================================================================
    // Getters
    //==========================================================================
    @Override
    public void setServletContext(ServletContext servletContext) {
        springServletContext = servletContext;
    }
    public Properties getJerseyConfiguration() {
        return jerseyConfiguration;
    }
    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    //==========================================================================
    // Setters
    //==========================================================================
    public ServletContext getSpringServletContext(){
        return springServletContext;
    }
    @Override
    public ServletContext getServletContext(){
        return this.getSpringServletContext();
    }
    public void setJerseyConfiguration(Properties jerseyConfiguration) {
        if( logger.isDebugEnabled() ){
            StringBuffer buffer = new StringBuffer();
            buffer.append("Setting jersey configuration:\n");
            for( Object key : jerseyConfiguration.keySet() ){
                buffer.append("\t").append(key).append("=").append(jerseyConfiguration.get(key)).append("\n");
            }
            logger.debug(buffer.toString());
        }
        this.jerseyConfiguration = jerseyConfiguration;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    //==========================================================================
    // Interfaces
    //==========================================================================
    @Override
    public ModelAndView handleRequest(
            HttpServletRequest request,
            HttpServletResponse response
    ) throws Exception {
        String uri = request.getRequestURI().substring(
                request.getContextPath().length(), request.getRequestURI().length());
        logger.info("Handling request {}, by passing it to parent jersey servlet...", uri);
        try{
            super.service(request, response);
        }catch(Throwable t){
            logger.error("An error occurred processing request: "+uri, t);
            throw new ServletException("The REST web service had an error. Please report this problem.", t);
        }
        logger.info("For path {}, returning DoNothingView...", uri);
        return new ModelAndView("DoNothingView");
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        final String fName = getClass().getName();
        final Properties fJerseyConfig = this.getJerseyConfiguration();
        logger.info("Initializing Bean {}...", fName);
        FilterConfig config = new FilterConfig() {
            @Override
            public ServletContext getServletContext() {
                return getSpringServletContext();
            }
            @Override
            public String getFilterName() {
                return fName;
            }
            @Override
            public Enumeration getInitParameterNames() {
                return fJerseyConfig.keys();
            }
            @Override
            public String getInitParameter(String paramName) {
                return fJerseyConfig.getProperty(paramName);
            }
        };
        
        logger.debug("Initializing Jersey through super.init(FilterConfig)...");
        super.init(config);
    }//end afterPropertiesSet()
        
}/* end JerseyIntegrationFilter */


Where the injected properties file looks like this:
# If true the request URI will be normalized as specified by
# {_at_link java.net.URI#normalize}. If not true the request URI is not
# modified.
# The default value is false.

com.sun.jersey.config.feature.NormalizeURI=true
    

# If true the request URI path component will be canonicalized by removing
# contiguous slashes (i.e. all /+ will be replaced by /). If not true the
# request URI path component is mot modified.
# The default value is false.

com.sun.jersey.config.feature.CanonicalizeURIPath=true
    

# If true, and either NORMALIZE_URI or CANONICALIZE_URI_PATH is true,
# and the normalization and/or path canonicalization operations on the
# request URI result in a new URI that is not equal to the request URI,
# then the client is (temporarily) redirected to the new URI. Otherwise
# the request URI is set to be the new URI.
# <p>
# If true, and the path value of a {_at_link javax.ws.rs.Path} annotation ends
# in a slash, the request URI path does not end in a '/' and would otherwise
# match the path value if it did, then the client is (temporarily)
# redirected to a new URI that is the request URI with a '/' appended to the
# the end of the path.
# <p>
# The default value is false.

com.sun.jersey.config.feature.Redirect=true
    
    
# If true matrix parameters (if present) in the request URI path component
# will be ignored when matching the path to URI templates declared by
# resource classes.
# <p>
# The default value is false.

#com.sun.jersey.config.feature.IgnoreMatrixParams=true
    
 
# If true then the matching algorithm will attempt to match and accept
# any static content or templates associated with a resource that were
# not explicitly decared by that resource.
# <p>
# If a template is matched then the model for the viewable will be the
# resource instance associated with the template.
# <p>
# The default value is false.

com.sun.jersey.config.feature.ImplicitViewables=true

    
# If true then disable WADL generation.
# <p>
# By default WADL generation is automatically enabled, if JAXB is
# present in the classpath.
# <p>
# The default value is false.

#com.sun.jersey.config.feature.DisableWADL=true

    


On Wed, Jan 13, 2010 at 4:02 PM, Mahesh Venkat <mhvenkat_at_gmail.com> wrote:

Hi Brad,
>
>
>Is it possible to share this working code?
>Also if you have an example of adding Spring interceptors that extend the Jersey ContainerFilters and Jersey ResourceFilters it will be great!
>
>
>In fact, in Spring 3.0 they are attempting do to take a similar approach to integrate with Jersey.
>
>
>We also have to some thing similar for Struts2 too. The Apache community is attempting to define yet another REST mechanism rather than integrating Jersey with Struts2.
>
>