Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure Jersey with Spring using only annotations

Tags:

spring

jersey

I have a Servlet 3.0 web app that uses both Spring and Jersey. I currently have it set up using the SpringServlet configured as a filter in web.xml, and the resource classes annotated with both @Path and @Component. Here's the web.xml snippet:

<filter>
    <filter-name>jersey-serlvet</filter-name>
    <filter-class>
        com.sun.jersey.spi.spring.container.servlet.SpringServlet
    </filter-class>
    <init-param>
        <param-name>
            com.sun.jersey.config.property.packages
        </param-name>
        <param-value>com.foo;com.bar</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.config.feature.FilterForwardOn404</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>jersey-serlvet</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

This setup works, but I really want to get this set up with annotations only - no web.xml config. My first attempt at this was to remove the above SpringServlet configuration and create a class that extends Application. Here's a snippet of that:

@ApplicationPath("/*")
public class MyApplication extends PackagesResourceConfig {

    public MyApplication() {
        super("com.foo;com.bar");

        HashMap<String, Object> settings = new HashMap<String, Object>(1);
        settings.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true);
        this.setPropertiesAndFeatures(settings);
    }
}

This works in that the JAX-RS resources are registered and I can hit them at their URLs, but they throw NullPointerExceptions when they try and use their autowired properties... this makes sense because I'm guessing the resources are now being loaded by Jersey and are not Spring managed beans, therefore no autowiring.

Despite a fair bit of searching around I cannot find any way of loading the Jersey resources as Spring beans with annotations only. Is there such a way? I don't really want to have to write a bunch of code for the resources to manually fetch the Spring context and invoke the DI if I can help it.

If annotations-only isn't going to work, then I can live with the filter config in web.xml if I can specify an Application class to load instead of a list of packages to scan. If I can get rid of the package list in there and just specify an Application class instance then I'll be content.

Obviously it would be great if someone had a definitive answer for me but I'd also be grateful for any pointers or hints of where else I could look or things to try.

Thanks, Matt

like image 433
Doughnuts Avatar asked Feb 06 '13 05:02

Doughnuts


People also ask

Can we use Jersey in spring boot?

The spring-boot-starter-jersey is a starter for building RESTful web applications using JAX-RS and Jersey. It is an alternative to spring-boot-starter-web . The spring-boot-starter-test is a starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito.

Does spring Use Jersey?

Spring Security can be used to secure a Jersey-based web application in much the same way as it can be used to secure a Spring MVC-based web application. However, if you want to use Spring Security's method-level security with Jersey, you must configure Jersey to use setStatus(int) rather sendError(int) .

What is Jersey config?

Jersey is an open source framework for developing RESTful Web Services. It serves as a reference implementation of JAX-RS. In this article, we'll explore the creation of a RESTful Web Service using Jersey 2. Also, we'll use Spring's Dependency Injection (DI) with Java configuration.


2 Answers

Below is part of my app, which uses Servlet 3.0, Spring, Jersey 1.8 and it has no web.xml:

public class WebAppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    context.setConfigLocation("com.myapp.config");

    final FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("characterEncodingFilter", new CharacterEncodingFilter());
    characterEncodingFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
    characterEncodingFilter.setInitParameter("encoding", "UTF-8");
    characterEncodingFilter.setInitParameter("forceEncoding", "true");

    final FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
    springSecurityFilterChain.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");

    servletContext.addListener(new ContextLoaderListener(context));
    servletContext.setInitParameter("spring.profiles.default", "production");

    final SpringServlet servlet = new SpringServlet();

    final ServletRegistration.Dynamic appServlet = servletContext.addServlet("appServlet", servlet);
    appServlet.setInitParameter("com.sun.jersey.config.property.packages", "com.myapp.api");
    appServlet.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", "com.myapp.api.SizeLimitFilter");
    appServlet.setLoadOnStartup(1);

    final Set<String> mappingConflicts = appServlet.addMapping("/api/*");

    if (!mappingConflicts.isEmpty()) {
        throw new IllegalStateException("'appServlet' cannot be mapped to '/' under Tomcat versions <= 7.0.14");
    }
}

}

like image 152
Igor Bljahhin Avatar answered Sep 20 '22 13:09

Igor Bljahhin


I haven't been able to get my ideal result but I have been able to make some progress, so I'll post here in case it helps anyone else. I was able to use the Spring Servlet to specify my application class, thereby removing the package list from the web.xml.

The web.xml changes required are in the init params (the filter mapping is not shown but is still required):

<filter>
    <filter-name>jersey-serlvet</filter-name>
    <filter-class>
        com.sun.jersey.spi.spring.container.servlet.SpringServlet
    </filter-class>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name> <!-- Specify application class here -->
        <param-value>com.foo.MyApplication</param-value>
    </init-param>
</filter>

And then in the application class I had to change the way I called the super constructor slightly:

public MyApplication() {
    super("com.foo", "com.bar"); // Pass in packages as separate params

    HashMap<String, Object> settings = new HashMap<String, Object>(1);
    settings.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true);
    this.setPropertiesAndFeatures(settings);
}

Still not exactly what I was after but at least this pulls a little more config into Java code and out of the web.xml, which is important for me as I'm trying to hide this detail.

like image 45
Doughnuts Avatar answered Sep 22 '22 13:09

Doughnuts