title: Dropwizard + Jersey : "Not inside a request scope" when creating custom annotation
body: <p>I have a simple Dropwizard 0.8.1 REST service that pulls in Jersey 2.17.  Upstream of the REST/Jetty service I have some authentication service that adds some nice authorization information to the HTTP Header that gets passed to my Dropwizard app.</p>
  
  <p>I would <em>love</em> to be able to create a custom annotation in my Resource that hides all the messy header-parsing-to-POJO garbage.  Something like this:</p>
  
  <pre><code> @Path("/v1/task")
   @Produces(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
   public class TaskResource {
  
        @UserContext                               // &lt;-- custom/magic annotation
        private UserContextData userContextData;   // &lt;-- holds all authorization info
  
        @GET
        public Collection&lt;Task&gt; fetch() {
             // use the userContextData to differentiate what data to return
        }
  </code></pre>
  
  <p>I've spent the last day looking around stackoverflow and found several other people who had the same issue and appeared (?) to get some satisfaction, but I can't seem to avoid getting a "Not inside a request scope" stack trace when I try to do this.</p>
  
  <p>So I stashed all my changes and tried to implement the example provided in sections 22.1 and 22.2 by the Jersey documentation directly: <a href="https://jersey.java.net/documentation/2.17/ioc.html" rel="nofollow">https://jersey.java.net/documentation/2.17/ioc.html</a></p>
  
  <p>Following along with their example (but in my Dropwizard app), I'm trying to get a "@SessionInject" annotation in my Resource, but it also blows up with "Not inside a request scope" stack trace each time.  What am I doing wrong here?</p>
  
  <p>Resource:</p>
  
  <pre><code>  @Path("/v1/task")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public class TaskResource {
  
         private final TaskDAO taskDAO;
  
         @Context
         private HttpServletRequest httpRequest;
  
         @SessionInject
         private HttpSession httpSession;
  
         public TaskResource(TaskDAO taskDAO) {
             this.taskDAO = taskDAO;
         }
  
         @GET
         public Collection&lt;Task&gt; fetch(@SessionInject HttpSession httpSession) {              
             if (httpSession != null) {
                  logger.info("TOM TOM TOM httpSession isn't null: {}", httpSession);
             }
             else {
                  logger.error("TOM TOM TOM httpSession is null");
             }
             return taskDAO.findAllTasks();
         }
  </code></pre>
  
  <p>The SessionInjectResolver:</p>
  
  <pre><code>package com.foo.admiral.integration.jersey;
  
  import com.foo.admiral.integration.core.SessionInject;
  import javax.inject.Inject;
  import javax.inject.Named;
  
  import javax.servlet.http.HttpSession;
  import org.glassfish.hk2.api.Injectee;
  
  import org.glassfish.hk2.api.InjectionResolver;
  import org.glassfish.hk2.api.ServiceHandle;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  public class SessionInjectResolver implements InjectionResolver&lt;SessionInject&gt; {
  
      private static final Logger logger = LoggerFactory.getLogger(HttpSessionFactory.class);
  
      @Inject
      @Named(InjectionResolver.SYSTEM_RESOLVER_NAME)
      InjectionResolver&lt;Inject&gt; systemInjectionResolver;
  
      @Override
      public Object resolve(Injectee injectee, ServiceHandle&lt;?&gt; handle) {
          if (HttpSession.class == injectee.getRequiredType()) {
              return systemInjectionResolver.resolve(injectee, handle);
          }
  
          return null;
      }
  
      @Override
      public boolean isConstructorParameterIndicator() {
          return false;
      }
  
      @Override
      public boolean isMethodParameterIndicator() {
          return false;
      }
  }
  </code></pre>
  
  <p>The HttpSessionFactory:</p>
  
  <pre><code>package com.foo.admiral.integration.jersey;
  
  import javax.inject.Inject;
  import javax.inject.Singleton;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  import org.glassfish.hk2.api.Factory;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  @Singleton
  public class HttpSessionFactory implements Factory&lt;HttpSession&gt; {
  
      private static final Logger logger = LoggerFactory.getLogger(HttpSessionFactory.class);
      private final HttpServletRequest request;
  
      @Inject
      public HttpSessionFactory(HttpServletRequest request) {
          logger.info("Creating new HttpSessionFactory with request");
          this.request = request;
      }
  
      @Override
      public HttpSession provide() {
          logger.info("Providing a new session if one does not exist");
          return request.getSession(true);
      }
  
      @Override
      public void dispose(HttpSession t) {
      }
  }
  </code></pre>
  
  <p>The annotation:</p>
  
  <pre><code>package com.foo.admiral.integration.core;
  
  import java.lang.annotation.ElementType;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.lang.annotation.Target;
  
  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.FIELD})
  public @interface SessionInject {
  }
  </code></pre>
  
  <p>And, finally, the binding in the Dropwizard Application class:</p>
  
  <pre><code>@Override
  public void run(TodoConfiguration configuration, Environment environment) throws Exception {
      ...
  
      environment.jersey().register(new AbstractBinder() {
          @Override
          protected void configure() {
              bindFactory(HttpSessionFactory.class).to(HttpSession.class);
  
              bind(SessionInjectResolver.class)
                      .to(new TypeLiteral&lt;InjectionResolver&lt;SessionInject&gt;&gt;() { })
                      .in(Singleton.class);
          }
      });
  </code></pre>
  
  <p>Ye old stack trace:</p>
  
  <pre><code>Caused by: java.lang.IllegalStateException: Not inside a request scope.
  at jersey.repackaged.com.google.common.base.Preconditions.checkState(Preconditions.java:149)
  at org.glassfish.jersey.process.internal.RequestScope.current(RequestScope.java:233)
  at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:158)
  at org.jvnet.hk2.internal.MethodInterceptorImpl.invoke(MethodInterceptorImpl.java:74)
  at org.jvnet.hk2.internal.MethodInterceptorInvocationHandler.invoke(MethodInterceptorInvocationHandler.java:62)
  at com.sun.proxy.$Proxy72.getSession(Unknown Source)
  at com.foo.admiral.integration.jersey.HttpSessionFactory.provide(HttpSessionFactory.java:29)
  at com.foo.admiral.integration.jersey.HttpSessionFactory.provide(HttpSessionFactory.java:14)
  </code></pre>
  
  <p>Some clues that may be useful:</p>
  
  <p>1)  I'm noticing is that the logging statements in my HttpSessionFactory are never getting fired, so I don't think the Factory is correctly identified to DropWizard.</p>
  
  <p>2)  If I change the annotation to be a Parameter instead of a Field and move the use of the annotation into the fetch( ) method signature like this, it doesn't throw the stack trace (but the httpSession is still null, presumably because the Factory isn't firing...)</p>
  
  <pre><code> public Collection&lt;Task&gt; fetch(@SessionInject HttpSession httpSession) {
  </code></pre>
  
  <p>3)  It doesn't appear to matter if I "register" the binder with environment.jersey().register() or environment.jersey().getResourceConfig().register()... they appear to do the same thing.</p>
  
  <p>Do you see any obvious problems?  Thanks in advance!</p>