jersey
  1. jersey
  2. JERSEY-1655

@BeanParam in singleton resource should be allowed on method as stated in JavaDoc.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Works as designed
    • Affects Version/s: 2.0-m11
    • Fix Version/s: 2.0-rc1, 2.0
    • Component/s: None
    • Labels:
      None
    • Environment:

      Unit Test, Jetty Programmatically

      Description

      @BeanParam in singleton resource should be allowed on methods as stated in JavaDoc.

      http://jersey.java.net/nonav/apidocs/snapshot/jersey/javax/ws/rs/BeanParam.html

      Because injection occurs at object creation time, use of this annotation on resource class fields and bean properties is only supported for the default per-request resource class lifecycle. Resource classes using other lifecycles should only use this annotation on resource method parameters.

          @Path( "/" )
          public static class TestResource
          {
              @POST
              @Path( "/sms" )
              @BeanParam
              public SmsResponse sms( @Context HttpServletRequest request )
              {
                  SmsResponse response = new SmsResponse();
                  response.setMessageId( "asdasd" );
                  return response;
              }
          }
      
          public class SmsResponse
          extends OneTimePasswordResponse
          {
              @HeaderParam( "provisioning-code" )
              private String provisioningCode;
          ....
      
      
              // started using embedded jetty..
              server = new Server( port );
              ServletContextHandler context = new ServletContextHandler( ServletContextHandler.NO_SESSIONS );
              context.setContextPath( "/" );
      
              ResourceConfig resourceConfig = new ResourceConfig();
              resourceConfig.registerInstances( new TestResource() );
              ServletContainer servletContainer = new ServletContainer( resourceConfig );
              ServletHolder servletHolder = new ServletHolder( servletContainer );
      
              context.addServlet( servletHolder, "/*" );
              server.setHandler( context );
              server.start();
      
      

      Results in:

      19:34:41.943 [main] WARN  / - unavailable
      java.lang.IllegalStateException: Not inside a request scope.
      	at com.google.common.base.Preconditions.checkState(Preconditions.java:149) ~[guava-13.0.jar:na]
      	at org.glassfish.jersey.process.internal.RequestScope.current(RequestScope.java:224) ~[jersey-common-2.0-m11.jar:na]
      	at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:152) ~[jersey-common-2.0-m11.jar:na]
      	at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:1931) ~[hk2-locator-2.1.51.jar:na]
      	at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:496) ~[hk2-locator-2.1.51.jar:na]
      	at org.jvnet.hk2.internal.IterableProviderImpl.get(IterableProviderImpl.java:87) ~[hk2-locator-2.1.51.jar:na]
      	at org.glassfish.jersey.internal.inject.ReferencingFactory.provide(ReferencingFactory.java:101) ~[jersey-common-2.0-m11.jar:na]
      	at org.jvnet.hk2.internal.FactoryCreator.create(FactoryCreator.java:96) ~[hk2-locator-2.1.51.jar:na]
      	at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:429) ~[hk2-locator-2.1.51.jar:na]
      	at org.jvnet.hk2.internal.PerLookupContext.findOrCreate(PerLookupContext.java:69) ~[hk2-locator-2.1.51.jar:na]
      	at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:1931) ~[hk2-locator-2.1.51.jar:na]
      	at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:496) ~[hk2-locator-2.1.51.jar:na]
      	at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:483) ~[hk2-locator-2.1.51.jar:na]
      	at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:185) ~[jersey-common-2.0-m11.jar:na]
      	at org.glassfish.jersey.server.internal.inject.BeanParamValueFactoryProvider$BeanParamValueFactory.get(BeanParamValueFactoryProvider.java:88) ~[jersey-server-2.0-m11.jar:na]
      	at org.glassfish.jersey.server.internal.inject.AbstractHttpContextValueFactory.provide(AbstractHttpContextValueFactory.java:67) ~[jersey-server-2.0-m11.jar:na]
      	at org.glassfish.jersey.server.internal.inject.ParamInjectionResolver.resolve(ParamInjectionResolver.java:134) ~[jersey-server-2.0-m11.jar:na]
      	at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:623) ~[hk2-locator-2.1.51.jar:na]
      	at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:687) ~[hk2-locator-2.1.51.jar:na]
      	at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:428) ~[jersey-server-2.0-m11.jar:na]
      	at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:144) ~[jersey-server-2.0-m11.jar:na]
      	at org.glassfish.jersey.server.ApplicationHandler$3.run(ApplicationHandler.java:263) ~[jersey-server-2.0-m11.jar:na]
      	at org.glassfish.jersey.internal.Errors$2.call(Errors.java:210) ~[jersey-common-2.0-m11.jar:na]
      	at org.glassfish.jersey.internal.Errors$2.call(Errors.java:207) ~[jersey-common-2.0-m11.jar:na]
      	at org.glassfish.jersey.internal.Errors.process(Errors.java:226) ~[jersey-common-2.0-m11.jar:na]
      	at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:207) ~[jersey-common-2.0-m11.jar:na]
      	at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:260) ~[jersey-server-2.0-m11.jar:na]
      	at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:254) ~[jersey-container-servlet-core-2.0-m11.jar:na]
      	at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:144) ~[jersey-container-servlet-core-2.0-m11.jar:na]
      	at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:326) ~[jersey-container-servlet-core-2.0-m11.jar:na]
      	at javax.servlet.GenericServlet.init(GenericServlet.java:244) ~[javax.servlet-api-3.0.1.jar:3.0.1]
      	at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:519) [jetty-servlet-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.servlet.ServletHolder.doStart(ServletHolder.java:331) [jetty-servlet-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64) [jetty-util-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:747) [jetty-servlet-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:265) [jetty-servlet-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:706) [jetty-server-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64) [jetty-util-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:95) [jetty-server-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.server.Server.doStart(Server.java:277) [jetty-server-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64) [jetty-util-8.1.8.v20121106.jar:8.1.8.v20121106]
      	at com.mm.camel.component.http.zeng.SendMessageTaskTest.before(SendMessageTaskTest.java:70) [test-classes/:na]
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_05]
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_05]
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_05]
      	at java.lang.reflect.Method.invoke(Method.java:601) ~[na:1.7.0_05]
      	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) [junit-4.11.jar:na]
      	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.11.jar:na]
      	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) [junit-4.11.jar:na]
      	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) [junit-4.11.jar:na]
      	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) [junit-4.11.jar:na]
      	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) [junit-4.11.jar:na]
      	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) [junit-4.11.jar:na]
      	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) [junit-4.11.jar:na]
      	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) [junit-4.11.jar:na]
      	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) [junit-4.11.jar:na]
      	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) [junit-4.11.jar:na]
      	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) [junit-4.11.jar:na]
      	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) [junit-4.11.jar:na]
      	at org.junit.runners.ParentRunner.run(ParentRunner.java:309) [junit-4.11.jar:na]
      	at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37) [mockito-core-1.9.5.jar:na]
      	at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62) [mockito-core-1.9.5.jar:na]
      	at org.junit.runner.JUnitCore.run(JUnitCore.java:160) [junit-4.11.jar:na]
      	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:76) [junit-rt.jar:na]
      	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195) [junit-rt.jar:na]
      	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63) [junit-rt.jar:na]
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_05]
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_05]
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_05]
      	at java.lang.reflect.Method.invoke(Method.java:601) ~[na:1.7.0_05]
      	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) [idea_rt.jar:na]
      
      

        Activity

        Hide
        Miroslav Fuksa added a comment -

        @BeanParam can be used on methods, but only for purpose of injections by setter methods. For example

        public static class MyBeanParam {
            @HeaderParam("par")
            public String header;
        }
        
        ...
        
        @Path("resource")
        public class TestResource {
        
            private MyBeanParam beanParam;
        
        
            // this method will be called during instantiation of the resource class
            // and parameter beanParam will be injected
            @BeanParam
            public void setBeanParam(MyBeanParam beanParam) {
                this.beanParam = beanParam;
            }
        
        ...
        }       
        

        This does work only in resource with the request scope lifecycle.

        Javadoc of BeanParam says:
        Because injection occurs at object creation time, use of this annotation on resource
        class fields and bean properties is only supported for the default per-request resource
        class lifecycle. *Resource classes using other lifecycles should only use this annotation
        on resource method parameters.*

        The usage for resource methods is not supported.

        Anyway, it is not clear to me, what exactly should be injected by BeanParam in the given example. HttpServletRequest is being injected and not a bean param. Bean param is then manually instantiated in the method, so there is again no place for injection.

        Show
        Miroslav Fuksa added a comment - @BeanParam can be used on methods, but only for purpose of injections by setter methods. For example public static class MyBeanParam { @HeaderParam( "par" ) public String header; } ... @Path( "resource" ) public class TestResource { private MyBeanParam beanParam; // this method will be called during instantiation of the resource class // and parameter beanParam will be injected @BeanParam public void setBeanParam(MyBeanParam beanParam) { this .beanParam = beanParam; } ... } This does work only in resource with the request scope lifecycle. Javadoc of BeanParam says: Because injection occurs at object creation time, use of this annotation on resource class fields and bean properties is only supported for the default per-request resource class lifecycle. *Resource classes using other lifecycles should only use this annotation on resource method parameters.* The usage for resource methods is not supported. Anyway, it is not clear to me, what exactly should be injected by BeanParam in the given example. HttpServletRequest is being injected and not a bean param. Bean param is then manually instantiated in the method, so there is again no place for injection.
        Hide
        aaronjwhiteside added a comment - - edited

        Oh, I was trying to indicate that the method returns a BeanParam object that should be used to generate the response. I guess that usage is not supported?

        The symmetry make sense, at least in my head. You can accept a bunch of HEADER parameters injected into a bean, so you should be able to return a bunch of HEADER parameters in a bean as a response?

        Doesn't it make more sense for a set method to have the annotation on the parameter, that would keep in line with the resource method usage? (I haven't yet read the JAX-RS 2.0 spec)

        Show
        aaronjwhiteside added a comment - - edited Oh, I was trying to indicate that the method returns a BeanParam object that should be used to generate the response. I guess that usage is not supported? The symmetry make sense, at least in my head. You can accept a bunch of HEADER parameters injected into a bean, so you should be able to return a bunch of HEADER parameters in a bean as a response? Doesn't it make more sense for a set method to have the annotation on the parameter, that would keep in line with the resource method usage? (I haven't yet read the JAX-RS 2.0 spec)
        Hide
        Marek Potociar added a comment -

        @BeanParam in JAX-RS spec is meant (as any other @<Nnn>Param) annotation for server-side injection of request values. The symmetry you are referring to would be in fact confusing, not to mention the increased complexity in the semantics of the annotation.

        Maybe it seems to work nicely for your single use case, but this idea is generally broken IMO.

        Show
        Marek Potociar added a comment - @BeanParam in JAX-RS spec is meant (as any other @<Nnn>Param ) annotation for server-side injection of request values . The symmetry you are referring to would be in fact confusing, not to mention the increased complexity in the semantics of the annotation. Maybe it seems to work nicely for your single use case, but this idea is generally broken IMO.
        Hide
        Miroslav Fuksa added a comment -

        Based on the previous comments I am closing this issue as it works as designed.

        Show
        Miroslav Fuksa added a comment - Based on the previous comments I am closing this issue as it works as designed.

          People

          • Assignee:
            Miroslav Fuksa
            Reporter:
            aaronjwhiteside
          • 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