jersey
  1. jersey
  2. JERSEY-2038

jersey-spring3 doesn't support Spring Java config properly

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Won't Fix
    • Affects Version/s: 2.2
    • Fix Version/s: None
    • Component/s: extensions
    • Labels:
    • Environment:

      Spring 3.2.3, Jersey 2.2-SNAPSHOT

      Description

      The new jersey-spring3 module expects an XML based spring configuration. I'm able to work around the issue when running the application by having the following WebApplicationInitializer:

      public class MyServiceWebAppInitializer implements WebApplicationInitializer {
      
          @Override
          public void onStartup(ServletContext container) {
              AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
              rootContext.register(MyServiceSpringConfig.class);
              container.addListener(new ContextLoaderListener(rootContext));
              container.addListener(new RequestContextListener());
      
              // The following line is required to avoid having jersey-spring3 registering it's own Spring root context.
              container.setInitParameter("contextConfigLocation", "");
          }
      }
      

      The last line makes jersey-spring3 skip initializing a new spring context in SpringWebApplicationInitializer (GitHub).

      When writing integration tests that extends from JerseyTest, however, this doesn't work. Using @RunWith(SpringJUnit4ClassRunner.class) and supplying my config class to @ContextConfiguration, jersey-spring3 still tries to initialize a ClassPathXmlApplicationContext in SpringComponentProvider (GitHub), and fails because the default applicationContext.xml file isn't found.

      Example code:

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes = MyServiceSpringConfig.class)
      public class MyIntegrationTest extends JerseyTest {
      
          @Override
          protected Application configure() {
              return new MyServiceJerseyConfig();
          }
      
          @Test
          public void someTest() throws Exception {
              // Very useful test
          }
      }
      

      The MyServiceJerseyConfig class:

      @ApplicationPath("webapi")
      public class MyServiceJerseyConfig extends ResourceConfig {
          public MyServiceJerseyConfig() {
              packages("com.acme.myservice");
          }
      }
      

        Activity

        Hide
        nyte added a comment -

        What is the reason that this has not been fixed for so long? It's been almost 2 years now...

        Show
        nyte added a comment - What is the reason that this has not been fixed for so long? It's been almost 2 years now...
        Hide
        maxn added a comment -

        I found a workaround that worked for my situation (I only want to use Spring for IoC). I couldn't find a way to do this in the Jersey ResourceConfig, and I ended up needing an extra WebApplicationInitializer.

        The @Priority is there to make sure it runs before the jersey-spring3 SpringWebApplicationInitializer.

        @Priority(value = 1)
        public class MySpringWebInitializer implements WebApplicationInitializer
        {
            @Override
            public void onStartup(ServletContext container)
            {
                //Tell jersey-spring3 the context is already initialized
                container.setInitParameter("contextConfigLocation", "NOTNULL");
                AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
                appContext.register(MySpringConfig.class);
                container.addListener(new ContextLoaderListener(appContext));
            }
        }
        
        Show
        maxn added a comment - I found a workaround that worked for my situation (I only want to use Spring for IoC). I couldn't find a way to do this in the Jersey ResourceConfig, and I ended up needing an extra WebApplicationInitializer. The @Priority is there to make sure it runs before the jersey-spring3 SpringWebApplicationInitializer. @Priority(value = 1) public class MySpringWebInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) { //Tell jersey-spring3 the context is already initialized container.setInitParameter( "contextConfigLocation" , "NOTNULL" ); AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); appContext.register(MySpringConfig.class); container.addListener( new ContextLoaderListener(appContext)); } }
        Hide
        kkrauth added a comment - - edited

        If you are using spring boot with jersey and plan to deploy the resulting WAR on a JBoss container, this issue will probably randomly bite you during startup. If the org.glassfish.jersey.server.spring.SpringWebApplicationInitializer is detected on the classpath first and runs before org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration initializer, you will most likely end up with a duplicate context exception. In a spring boot app that already extends the SpringBootServletInitializer, all you need is this:

        @Priority(value = 1)
        public class MySpringWebInitializer implements WebApplicationInitializer
        {
            @Override
            public void onStartup(ServletContext container)
            {
                //Tell jersey-spring3 the context is already initialized
                container.setInitParameter("contextConfigLocation", "NOTNULL");
            }
        }
        

        It took a while to figure this out, so I agree with above posters that this should not be marked as minor. It outright breaks spring boot apps with jersey when deployed on servlet containers.

        Show
        kkrauth added a comment - - edited If you are using spring boot with jersey and plan to deploy the resulting WAR on a JBoss container, this issue will probably randomly bite you during startup. If the org.glassfish.jersey.server.spring.SpringWebApplicationInitializer is detected on the classpath first and runs before org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration initializer, you will most likely end up with a duplicate context exception. In a spring boot app that already extends the SpringBootServletInitializer, all you need is this: @Priority(value = 1) public class MySpringWebInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) { //Tell jersey-spring3 the context is already initialized container.setInitParameter( "contextConfigLocation" , "NOTNULL" ); } } It took a while to figure this out, so I agree with above posters that this should not be marked as minor. It outright breaks spring boot apps with jersey when deployed on servlet containers.
        Hide
        stu_s added a comment - - edited

        I tried the workarounds suggested above, but it looks like the priority annotation is not being respected (I also tried @Order, since it looks like spring-jersey pulls in pre-4.1 spring versions):

        INFO: Spring WebApplicationInitializers detected on classpath: [org.glassfish.jersey.server.spring.SpringWebApplicationInitializer@49357096, com.openx.tq.adquality.cbir.gateway.SpringApplicationInitializer@5372ad66]
        Dec 29, 2015 6:55:02 PM org.apache.catalina.core.ApplicationContext log
        INFO: Initializing Spring root WebApplicationContext
        Dec 29, 2015 6:55:03 PM org.apache.catalina.core.StandardContext listenerStart
        SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
        org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [applicationContext.xml]; nested exception is java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist
        

        I still need to try the workaround suggested by @kknd22 ... but it would be nice to know why the jersey folks don't feel this is an issue - why in the world would you force the use of an xml based configuration in a framework designed to support a spec (JAX-RS) where the whole point of the framework is to avoid xml configuration in favor of annotation based configuration?

        The logic of the design choice (including the obvious rejection of the idea that this issue is a genuine bug, considering the years this issue has sat around) is bizarre to say the least.

        It should be noted that I'd actually prefer to use as little spring as possible, and generally prefer solutions that hew closer to java standards, but this bug may force me away from jersey and back into springs web framework sigh.

        Show
        stu_s added a comment - - edited I tried the workarounds suggested above, but it looks like the priority annotation is not being respected (I also tried @Order, since it looks like spring-jersey pulls in pre-4.1 spring versions): INFO: Spring WebApplicationInitializers detected on classpath: [org.glassfish.jersey.server.spring.SpringWebApplicationInitializer@49357096, com.openx.tq.adquality.cbir.gateway.SpringApplicationInitializer@5372ad66] Dec 29, 2015 6:55:02 PM org.apache.catalina.core.ApplicationContext log INFO: Initializing Spring root WebApplicationContext Dec 29, 2015 6:55:03 PM org.apache.catalina.core.StandardContext listenerStart SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [applicationContext.xml]; nested exception is java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist I still need to try the workaround suggested by @kknd22 ... but it would be nice to know why the jersey folks don't feel this is an issue - why in the world would you force the use of an xml based configuration in a framework designed to support a spec (JAX-RS) where the whole point of the framework is to avoid xml configuration in favor of annotation based configuration? The logic of the design choice (including the obvious rejection of the idea that this issue is a genuine bug, considering the years this issue has sat around) is bizarre to say the least. It should be noted that I'd actually prefer to use as little spring as possible, and generally prefer solutions that hew closer to java standards, but this bug may force me away from jersey and back into springs web framework sigh .
        Hide
        Stepan Vavra added a comment -

        I'm sorry guys, but we (the Jersey team) cannot dedicate resources to fix Spring related issues (including this one) at the moment. In case you feel strongly about the issue, please consider contributing a fix by submitting a Github pull request.

        We look forward to see the community contributing to Spring Jersey related issues and features!
        Thanks!
        Stepan

        Show
        Stepan Vavra added a comment - I'm sorry guys, but we (the Jersey team) cannot dedicate resources to fix Spring related issues (including this one) at the moment. In case you feel strongly about the issue, please consider contributing a fix by submitting a Github pull request. We look forward to see the community contributing to Spring Jersey related issues and features! Thanks! Stepan

          People

          • Assignee:
            Stepan Vavra
            Reporter:
            jervi
          • Votes:
            30 Vote for this issue
            Watchers:
            29 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: