2014-02-19 24 views
2

我有一个基于令牌的用户验证的新泽西州的REST应用。当收到请求时,定制RestContext对象被创建并添加到ContainerRequestContext作为属性(通过运行接收到请求之后立即过滤器)。此上下文管理用户授权(通过角色)和对其他业务逻辑的访问。它在资源中可用于执行业务逻辑。当处理请求时,RestContext会在管道最后执行的第二个过滤器中清除。如何定义上下文绑定到新泽西请求

这工作得很好,虽然它需要两个过滤器。我一直在阅读关于使用HK2和InjectionResolver,我想知道如果我可以使用注射注入这个RestContext在我的资源和其他过滤器(例如我有一个创建从RestContext一个SecurityContext过滤器),但我不能” t找到答案。一般来说,如何根据请求上下文为每个请求注入一个对象?这甚至有可能吗?有没有更简单的方法来做到这一点,例如,使用@Context

编辑:正如指出的那样,我基本上是试图在我的资源沿着the documentation线注入的自定义类。但是,我似乎无法正确注册我的AbstractBinder以绑定我的课程的注入。我得到如下:

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=RestContext,parent=RestContextFilter,qualifiers={}),position=0,optional=false,self=false,unqualified=null,1435496015) 

编辑 2:我设法让一些轻微的进步。创建我以下列方式配置:

new ResourceConfig(allResources()) 
    .packages(packagesToScan()) 
    .registerInstances(new RestContextBinder()); 

由于文件明确指出,粘合剂的注入是not supported via class but via instance

但是我现在得到这个:

A MultiException has 3 exceptions. They are: 
1. java.lang.IllegalStateException: Not inside a request scope. 
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of my.package.RestContextFilter errors were found 
3. java.lang.IllegalStateException: Unable to perform operation: resolve on my.package.RestContextFilter 

的RestContext是@Inject在请求/响应滤波器-ed。然后用它创建一个SecurityContext并将其设置在ContainerRequestContext中,并在响应过滤器中进行清理。没有响应过滤器请求的作用域?为什么我会收到错误?

+0

我不确定在泽西岛内做到这一点的正确方法。话虽如此,我认为如果你能找到Jersey的Jersey实现,你可以编写自己的InjectionResolver来注入Jersey。如果你让你的Context具有比Jersey注入解析器更高的优先级,它将被选作泽西岛之前的解析器。然后,您可以随意增强泽西岛解析器,而当您不需要时,只需将泽西岛上下文方法作为后备方法 – jwells131313

+0

哇,这听起来很不可靠!我想我会坚持这种方法,直到我找到一些更主流的东西。这并不值得。 –

+0

我可能会误解你的问题,但我相信你想要做类似的事情。 '配置(RestContext.class).in(RequestScoped.class)'。这将允许您执行'@Inject RestContext ctx;'并确保每个请求只有一个实例存在。您可以将其注入您的过滤器并设置必要的信息,然后根据需要将其注入到其他地方。你不需要在'ContainerRequestContext'上设置任何东西,只需要注入'RestContext'。你也不需要清理任何东西。这是你在找什么?如果是这样,我可以添加它作为答案。 – Alden

回答

6

UPDATE现在泽西2.7已经出来了,解决的办法是简单。

这听起来像你想有一个RequestScoped约束力。下面是如何设置的事情了泽西岛2.7:

您将需要请求过滤器,因为RestContextRequestScoped,你可以注入一个供应商到过滤器,就可以设置一些属性,并且知道他们会可用于剩余的请求。

@Priority(Priorities.AUTHORIZATION) // filter deals with roles, comes after AUTHENTICATION 
public class RestContextFilter implements ContainerRequestFilter 
{ 
    // you need to inject a provider, rather than the class directly 
    // because this filter is instantiated before the request scope is ready 
    private Provider<RestContext> rcProvider; 

    @Inject 
    public RestContextFilter(Provider<RestContext> rcProvider) 
    { 
     this.rcProvider = rcProvider; 
    } 

    @Override 
    public void filter(ContainerRequestContext requestContext) throws IOException 
    { 
     // now you're in a request scope and can get your context 
     RestContext rc = rcProvider.get(); 

     // set some properties on rc here (current user or roles or whatever) 
    } 
} 

您需要使用HK2结合在ResourceConfig注册的过滤器,并绑定RestContext

public class MyResourceConfig extends ResourceConfig 
{ 
    public MyResourceConfig() 
    { 
     register(RestContextFilter.class); 

     register(new AbstractBinder() 
     { 
      @Override 
      protected void configure() 
      { 
       bindFactory(new Factory<RestContext>() 
       { 
        @Override 
        public RestContext provide() 
        { 
         return new RestContext(); 
        } 

        // this will get called at the end of the request 
        // allowing you to close your request scoped object 
        @Override 
        public void dispose(RestContext instance) 
        { 
         instance.close(); 
        } 
       }, RequestScoped.class).to(RestContext.class).in(RequestScoped.class); 
      } 
     }); 
    } 
} 

然后你可以注入你的资源RestContext,它将都设立了信息的通过你的过滤器。例如:

@Path("/my/path") 
public class MyResource 
{ 
    private RestContext rc; 

    @Inject 
    public MyResource(RestContext rc) 
    { 
     this.rc = rc; 
    } 

    @POST 
    @Consumes(MediaType.APPLICATION_JSON) 
    public void upload(MyPostObj data) 
    { 
     // do stuff here, and rc is all set up 
    } 
} 

我倾向于更喜欢构造函数注入过场注入,因为我觉得它使你的依赖其他开发者阅读你的代码更加明显。如果我的支撑风格让你烦恼,也很抱歉,我来自.NET的奇妙世界:)。

+0

看起来真棒。将尝试它并回来。 –

+0

因此,如果我有一个构造函数'RestContext(ContainerRequestContext)',我可以用'@Inject'来注释它,让Jersey在创建时注入请求上下文吗? –

+0

其实我得到了:'org.glassfish.hk2.api.UnsatisfiedDependencyException:Injectee中没有可用于注入的对象(r​​equiredType = RestContext,parent = RestContextFilter,qualifiers = {}),position = 0,optional = false,自=假,不合格= NULL,1983762179)'。我的绑定不起作用?我在我的'ResourceConfig'对象的构造函数中的类列表中添加了一个'RestContextBinder.class'。这不会起作用吗? –