Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Dropwizard+;泽西岛:“;“不在请求范围内”;创建自定义注释时_Java_Annotations_Jersey_Dropwizard - Fatal编程技术网

Java Dropwizard+;泽西岛:“;“不在请求范围内”;创建自定义注释时

Java Dropwizard+;泽西岛:“;“不在请求范围内”;创建自定义注释时,java,annotations,jersey,dropwizard,Java,Annotations,Jersey,Dropwizard,我有一个简单的Dropwizard 0.8.1 REST服务,它支持Jersey 2.17。在REST/Jetty服务的上游,我有一些身份验证服务,它向传递到Dropwizard应用程序的HTTP头添加了一些不错的授权信息 我希望能够在我的资源中创建一个自定义注释,隐藏对POJO垃圾的所有混乱的头解析。大概是这样的: @Path("/v1/task") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION

我有一个简单的Dropwizard 0.8.1 REST服务,它支持Jersey 2.17。在REST/Jetty服务的上游,我有一些身份验证服务,它向传递到Dropwizard应用程序的HTTP头添加了一些不错的授权信息

我希望能够在我的资源中创建一个自定义注释,隐藏对POJO垃圾的所有混乱的头解析。大概是这样的:

 @Path("/v1/task")
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
 public class TaskResource {

      @UserContext                               // <-- custom/magic annotation
      private UserContextData userContextData;   // <-- holds all authorization info

      @GET
      public Collection<Task> fetch() {
           // use the userContextData to differentiate what data to return
      }
最后,Dropwizard应用程序类中的绑定:

@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);
        }
    });
一些可能有用的线索:

1) 我注意到,我的HttpSessionFactory中的日志语句从未被触发,因此我认为该工厂没有正确标识为DropWizard

2) 如果我将注释更改为参数而不是字段,并像这样将注释的使用移动到fetch()方法签名中,它不会抛出堆栈跟踪(但httpSession仍然为null,可能是因为工厂没有触发…)

公共集合获取(@SessionInject-HttpSession-HttpSession){
3) 我是否使用environment.jersey().register()或environment.jersey().getResourceConfig().register()来“注册”绑定器似乎无关紧要……它们似乎做了同样的事情


您看到任何明显的问题了吗?提前谢谢!

这是一种奇怪的行为。但下面是发生的情况

  • 您已将
    TaskResource
    注册为一个实例,而不是
    .class
    。这一点我很确定(尽管您没有提到)

    执行前者时,它将资源设置在单例作用域中。后者设置在请求作用域中(除非另有注释,请参见下文)

  • 当资源模型加载时,它会看到
    TaskResource
    是一个单例,并且
    HttpServletRequest
    在一个请求范围内。要么工厂在一个每个请求范围内。我猜是这两个范围之一

  • 我认为这实际上可能是一个范围问题,正如错误消息中提到的,但我非常确定的是,在运行时,它将通过线程本地代理处理,因为范围较小

    您可以通过将
    任务资源
    注册为一个类,然后用
    @Singleton
    注释
    任务资源
    来修复它。如果您确实希望资源类是一个单例,那么就不要使用
    @Singleton

    对我来说,奇怪的是,当资源在启动时显式实例化时,它在启动时失败,但当框架在第一个请求上加载时(这是将其注册为类时发生的情况),它就工作了。它们都仍然在单例范围内

    您可能需要考虑的一件事是,您是否真的希望资源为单例。您确实需要担心单例的线程安全问题,并且还有一些其他限制。就个人而言,我更喜欢将它们保留在请求范围内。您必须进行一些性能测试,以查看是否存在这些限制这对您的应用程序有很大影响

    更新 对于参数注入,您可能需要查看

    更新2 另请参见

    • 1.我的回答应该会让你更清楚一些

    我希望能够在我的资源中创建一个自定义注释,隐藏对POJO垃圾的所有凌乱头解析。这是什么意思?对POJO垃圾的凌乱头解析是什么?是一条消息(或一组消息)在日志或类似内容中?我的意思是,有一个HTTP头,其中包含一个大的JSON blob,几乎每个资源和端点都需要它。我不希望将@HttpHeader参数传递给每个端点方法签名,我更希望在“幕后”进行所有头JSON到POJO的解析.您是如何将
    任务资源
    注册为实例还是
    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;
        }
    }
    
    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 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) {
        }
    }
    
    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 {
    }
    
    @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);
            }
        });
    
    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)
    
     public Collection<Task> fetch(@SessionInject HttpSession httpSession) {
    
    register(new TaskResource()); 
    /* instead of */ 
    register(TaskResource.class);