jersey
  1. jersey
  2. JERSEY-1119

@Stateless does not work with @MatrixParam

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Blocker Blocker
    • Resolution: Invalid
    • Affects Version/s: 2.0-m09
    • Fix Version/s: 2.0-rc1, 2.0
    • Component/s: core
    • Labels:
      None

      Description

      Spec. Section 10.2 says:
      In a product that also supports EJB, an implementation MUST support use of stateless and singleton
      session beans as root resource classes.

      Suppose a resource:

      @javax.ejb.Stateless
      @Path("/ssb")
      public class StatelessRootResource {
      	@MatrixParam(value = "matrix")
      	String matrix;
      	@Path("nokeyword")
      	@GET
      	public String noInjectOrResourceKeyword() {
      		return matrix;
      	}
      }
      

      There is an exception when calling any method from the resource:

      #|2012-04-23T14:27:17.602+0200|SEVERE|glassfish3.1.2|com.sun.jersey.spi.inject.Errors|_ThreadID=24;_ThreadName=Thread-2;|The following errors and warnings have been detected with resource and/or provider classes:
      SEVERE: Missing dependency for field: java.lang.String com.sun.ts.tests.jaxrs.platform.ejbsingleton.SingletonRootResource.matrix|#]

      [#|2012-04-23T14:27:17.657+0200|WARNING|glassfish3.1.2|javax.enterprise.system.container.ejb.com.sun.ejb.containers|_ThreadID=24;_ThreadName=Thread-2;|EJB5184:A system exception occurred during an invocation on EJB SingletonRootResource, method: public java.lang.String com.sun.ts.tests.jaxrs.platform.ejbsingleton.SingletonRootResource.throwException()|#]

      [#|2012-04-23T14:27:17.658+0200|WARNING|glassfish3.1.2|javax.enterprise.system.container.ejb.com.sun.ejb.containers|_ThreadID=24;_ThreadName=Thread-2;|javax.ejb.EJBException: javax.ejb.CreateException: Initialization failed for Singleton SingletonRootResource
      at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.create(AbstractSingletonContainer.java:721)
      at com.sun.ejb.containers.AbstractSingletonContainer.instantiateSingletonInstance(AbstractSingletonContainer.java:451)
      at org.glassfish.ejb.startup.SingletonLifeCycleManager.initializeSingleton(SingletonLifeCycleManager.java:216)
      at org.glassfish.ejb.startup.SingletonLifeCycleManager.initializeSingleton(SingletonLifeCycleManager.java:177)
      at com.sun.ejb.containers.AbstractSingletonContainer.checkInit(AbstractSingletonContainer.java:423)
      at com.sun.ejb.containers.CMCSingletonContainer._getContext(CMCSingletonContainer.java:117)
      at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:2547)
      at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1899)
      at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
      at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
      at $Proxy319.throwException(Unknown Source)
      at com.sun.ts.tests.jaxrs.platform.ejbsingleton._EJB31_GeneratedSingletonRootResourceIntf__Bean_.throwException(Unknown Source)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
      at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
      at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
      at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
      at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
      at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
      at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
      at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
      at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1483)
      at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1414)
      at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
      at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
      at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
      at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:538)
      at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:716)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
      at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
      at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
      at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
      at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
      at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
      at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
      at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746)
      at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045)
      at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228)
      at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
      at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
      at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
      at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
      at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
      at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
      at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
      at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
      at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
      at java.lang.Thread.run(Thread.java:662)
      Caused by: javax.ejb.CreateException: Initialization failed for Singleton SingletonRootResource
      at com.sun.ejb.containers.AbstractSingletonContainer.createSingletonEJB(AbstractSingletonContainer.java:547)
      at com.sun.ejb.containers.AbstractSingletonContainer.access$100(AbstractSingletonContainer.java:79)
      at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.create(AbstractSingletonContainer.java:719)
      ... 54 more
      Caused by: com.sun.jersey.spi.inject.Errors$ErrorMessagesException
      at com.sun.jersey.spi.inject.Errors.processErrorMessages(Errors.java:170)
      at com.sun.jersey.spi.inject.Errors.postProcess(Errors.java:136)
      at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:199)
      at com.sun.jersey.server.impl.application.WebApplicationImpl$ComponentProcessorFactoryImpl.get(WebApplicationImpl.java:501)
      at com.sun.jersey.server.impl.ejb.EJBInjectionInterceptor.get(EJBInjectionInterceptor.java:104)
      at com.sun.jersey.server.impl.ejb.EJBInjectionInterceptor.init(EJBInjectionInterceptor.java:71)
      at sun.reflect.GeneratedMethodAccessor359.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCallback(SystemInterceptorProxy.java:133)
      at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.init(SystemInterceptorProxy.java:120)
      at sun.reflect.GeneratedMethodAccessor358.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at com.sun.ejb.containers.interceptors.CallbackInterceptor.intercept(InterceptorManager.java:964)
      at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:65)
      at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:393)
      at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:376)
      at com.sun.ejb.containers.AbstractSingletonContainer.createSingletonEJB(AbstractSingletonContainer.java:538)
      ... 56 more

        Issue Links

          Activity

          Hide
          Martin Matula added a comment -

          There is a scope mismatch. So I am guessing this works as designed. You would have to inject the matrix param into a method parameter rather than an instance field in case of a singleton. Assigning to Jakub to confirm.

          Show
          Martin Matula added a comment - There is a scope mismatch. So I am guessing this works as designed. You would have to inject the matrix param into a method parameter rather than an instance field in case of a singleton. Assigning to Jakub to confirm.
          Hide
          jan.supol added a comment -

          The log is from @Singleton, granted, my bad. But for @Stateless, the log looks similar and behaviour is the same.

          Show
          jan.supol added a comment - The log is from @Singleton, granted, my bad. But for @Stateless, the log looks similar and behaviour is the same.
          Hide
          Jakub Podlesak added a comment -

          Confirmed as reproducible even with a stateless bean. It is indeed caused by scope mismatch.
          Jersey EJBInjectionInterceptor calculates a wrong scope here (line 99):

          final ComponentScope cs = c.isAnnotationPresent(ManagedBean.class)
          ? c.isAnnotationPresent(Provider.class)
          ? ComponentScope.Singleton
          : cpf.getScope(c)
          : ComponentScope.Singleton;

          Need to fix the above scope calculation. The last line (returns Singleton) is used even for @Stateless annotated beans.
          The following quick hack fixes the issue:

          final ComponentScope cs = c.isAnnotationPresent(ManagedBean.class)
          ? c.isAnnotationPresent(Provider.class)
          ? ComponentScope.Singleton
          : cpf.getScope(c)
          : c.isAnnotationPresent(Stateless.class) ?
          ComponentScope.PerRequest : ComponentScope.Singleton;

          but we need to: add tests + workout a better fix

          Show
          Jakub Podlesak added a comment - Confirmed as reproducible even with a stateless bean. It is indeed caused by scope mismatch. Jersey EJBInjectionInterceptor calculates a wrong scope here (line 99): final ComponentScope cs = c.isAnnotationPresent(ManagedBean.class) ? c.isAnnotationPresent(Provider.class) ? ComponentScope.Singleton : cpf.getScope(c) : ComponentScope.Singleton; Need to fix the above scope calculation. The last line (returns Singleton) is used even for @Stateless annotated beans. The following quick hack fixes the issue: final ComponentScope cs = c.isAnnotationPresent(ManagedBean.class) ? c.isAnnotationPresent(Provider.class) ? ComponentScope.Singleton : cpf.getScope(c) : c.isAnnotationPresent(Stateless.class) ? ComponentScope.PerRequest : ComponentScope.Singleton; but we need to: add tests + workout a better fix
          Hide
          jan.supol added a comment -

          Already fixed.

          Show
          jan.supol added a comment - Already fixed.
          Hide
          jan.supol added a comment - - edited

          Trying that now, it does not inject anything to @MatrixParam for GET requests. For POST it does work.

          Show
          jan.supol added a comment - - edited Trying that now, it does not inject anything to @MatrixParam for GET requests. For POST it does work.
          Hide
          Jakub Podlesak added a comment -

          Matrix param injection works fine for me.

          The issue is even stateless beans are handled as singletons,
          i.e. field parameter injection works only for the very first request.

          This seems to be an issue with JNDI EJB lookup, as i have checked
          Jersey does the lookup correctly with each request.

          Further work on this will be done as part of JERSEY-1749., where
          it is believed JNDI lookup could be replaced with bean manager api calls.
          However, the above mentioned JNDI lookup regression also needs to be clarified
          with EJB guys.

          Show
          Jakub Podlesak added a comment - Matrix param injection works fine for me. The issue is even stateless beans are handled as singletons, i.e. field parameter injection works only for the very first request. This seems to be an issue with JNDI EJB lookup, as i have checked Jersey does the lookup correctly with each request. Further work on this will be done as part of JERSEY-1749 ., where it is believed JNDI lookup could be replaced with bean manager api calls. However, the above mentioned JNDI lookup regression also needs to be clarified with EJB guys.
          Hide
          Jakub Podlesak added a comment - - edited

          After consulting the spec documents once again, closing this one as invalid.

          Short version: method parameter injection must be used also in stateless session bean case

          A bit longer version:

          1) Stateless session beans are not guaranteed to be managed in a per request manner.
          On the contrary, requests coming in a sequence will most likely see the very same bean instance.
          The container should typically only guarantee that requests made in parallel, at the same time,
          would not share a single bean instance.

          Given the above it does not make any sense to rely on field injected request related stuff.

          2) Field and property injection of matrix parameters is not mandated
          by the JAX-RS spec (for EJB beans),
          so even if (1) did not hold (as it does), the bug would be invalid.
          Method parameter injection works for me just fine.

          Show
          Jakub Podlesak added a comment - - edited After consulting the spec documents once again, closing this one as invalid. Short version: method parameter injection must be used also in stateless session bean case A bit longer version: 1) Stateless session beans are not guaranteed to be managed in a per request manner. On the contrary, requests coming in a sequence will most likely see the very same bean instance. The container should typically only guarantee that requests made in parallel, at the same time, would not share a single bean instance. Given the above it does not make any sense to rely on field injected request related stuff. 2) Field and property injection of matrix parameters is not mandated by the JAX-RS spec (for EJB beans), so even if (1) did not hold (as it does), the bug would be invalid. Method parameter injection works for me just fine.
          Hide
          Jakub Podlesak added a comment -

          fixed remaining estimate

          Show
          Jakub Podlesak added a comment - fixed remaining estimate

            People

            • Assignee:
              Jakub Podlesak
              Reporter:
              jan.supol
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Time Tracking

                Estimated:
                Original Estimate - 3 hours
                3h
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 2 hours Time Not Required
                2h