java - Dropwizard + Jersey : "Not inside a request scope" when creating custom annotation -


i have simple dropwizard 0.8.1 rest service pulls in jersey 2.17. upstream of rest/jetty service have authentication service adds nice authorization information http header gets passed dropwizard app.

i love able create custom annotation in resource hides messy header-parsing-to-pojo garbage. this:

 @path("/v1/task")  @produces(mediatype.application_json)  @consumes(mediatype.application_json)  public class taskresource {        @usercontext                               // <-- custom/magic annotation       private usercontextdata usercontextdata;   // <-- holds authorization info        @get       public collection<task> fetch() {            // use usercontextdata differentiate data return       } 

i've spent last day looking around stackoverflow , found several other people had same issue , appeared (?) satisfaction, can't seem avoid getting "not inside request scope" stack trace when try this.

so stashed changes , tried implement example provided in sections 22.1 , 22.2 jersey documentation directly: https://jersey.java.net/documentation/2.17/ioc.html

following along example (but in dropwizard app), i'm trying "@sessioninject" annotation in resource, blows "not inside request scope" stack trace each time. doing wrong here?

resource:

  @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<task> fetch(@sessioninject httpsession httpsession) {                          if (httpsession != null) {                 logger.info("tom tom tom httpsession isn't null: {}", httpsession);            }            else {                 logger.error("tom tom tom httpsession null");            }            return taskdao.findalltasks();        } 

the sessioninjectresolver:

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<sessioninject> {      private static final logger logger = loggerfactory.getlogger(httpsessionfactory.class);      @inject     @named(injectionresolver.system_resolver_name)     injectionresolver<inject> systeminjectionresolver;      @override     public object resolve(injectee injectee, servicehandle<?> 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;     } } 

the httpsessionfactory:

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<httpsession> {      private static final logger logger = loggerfactory.getlogger(httpsessionfactory.class);     private final httpservletrequest request;      @inject     public httpsessionfactory(httpservletrequest request) {         logger.info("creating new httpsessionfactory request");         this.request = request;     }      @override     public httpsession provide() {         logger.info("providing new session if 1 not exist");         return request.getsession(true);     }      @override     public void dispose(httpsession t) {     } } 

the annotation:

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 { } 

and, finally, binding in dropwizard application class:

@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<injectionresolver<sessioninject>>() { })                     .in(singleton.class);         }     }); 

ye old stack trace:

caused by: java.lang.illegalstateexception: not inside request scope. @ jersey.repackaged.com.google.common.base.preconditions.checkstate(preconditions.java:149) @ org.glassfish.jersey.process.internal.requestscope.current(requestscope.java:233) @ org.glassfish.jersey.process.internal.requestscope.findorcreate(requestscope.java:158) @ org.jvnet.hk2.internal.methodinterceptorimpl.invoke(methodinterceptorimpl.java:74) @ org.jvnet.hk2.internal.methodinterceptorinvocationhandler.invoke(methodinterceptorinvocationhandler.java:62) @ com.sun.proxy.$proxy72.getsession(unknown source) @ com.foo.admiral.integration.jersey.httpsessionfactory.provide(httpsessionfactory.java:29) @ com.foo.admiral.integration.jersey.httpsessionfactory.provide(httpsessionfactory.java:14) 

some clues may useful:

1) i'm noticing logging statements in httpsessionfactory never getting fired, don't think factory correctly identified dropwizard.

2) if change annotation parameter instead of field , move use of annotation fetch( ) method signature this, doesn't throw stack trace (but httpsession still null, presumably because factory isn't firing...)

 public collection<task> fetch(@sessioninject httpsession httpsession) { 

3) doesn't appear matter if "register" binder environment.jersey().register() or environment.jersey().getresourceconfig().register()... appear same thing.

do see obvious problems? in advance!

this weird behavior. looks going on following

  1. you have registered taskresource instance , not .class. i'm pretty sure of (though have not mentioned).

    register(new taskresource());  /* instead of */  register(taskresource.class); 

    doing former, set resource in singleton scope. latter in request scope (unless annotated otherwise - see below)

  2. when resource model loading sees taskresource singleton, , httpservletrequest in request scope. either or factory in per request scope. i'm guessing 1 of two.

i thought might be scope issue, mentioned in error message, i'm pretty sure of @ runtime, handled thread local proxy, because of lesser scope.

you can see fixed registering taskresource class, , annotating taskresource @singleton. if do want resource class singleton. if not, leave off @singleton.

the odd thing me fact fails on startup when resource explicitly instantiated on startup, works when framework loads on first request (which happens when register class). both still in singleton scope.

one thing might want take consideration whether want resource singleton or not. have worry thread safety issues singletons, , there are other limitations. personally, prefer keep them in request scope. have performance testing see if there of impact application.

update

for parameter injection may want take @ this post

update 2

see also


Comments

Popular posts from this blog

javascript - Bootstrap Popover: iOS Safari strange behaviour -

Magento/PHP - Get phones on all members in a customer group -

session - Logging Out Using PHP -