自定义提供程序无法注入过滤器

时间:2013-03-25 22:06:37

标签: java jersey jax-rs jersey-1.0

我有一个POJO,我想注入资源和过滤器:

public final class MyObject { }

我为它实现了一个自定义提供程序:

@Provider
public final class MyProvider
extends AbstractHttpContextInjectable<MyObject>
implements InjectableProvider<Context, Type> {

    @Context private HttpServletRequest request;

    @Override
    public Injectable<MyObject> getInjectable(
            ComponentContext componentContext,
            Context annotation,
            Type type
    ) {
        if (type.equals(MyObject.class)) {
            return this;
        }
        return null;
    }

    @Override
    public ComponentScope getScope() {
        return ComponentScope.PerRequest;
    }

    @Override
    public MyObject getValue(HttpContext httpContext) {
        //in reality, use session info from injected request to create MyObject
        return new MyObject();
    }
}

该对象已成功注入我的资源:

@Path("/test")
@ResourceFilters(MyFilter.class)
public final class MyResource {

    @Context private HttpServletRequest request;
    @Context private MyObject myObject;

    @GET
    public String execute() {

        System.out.println(request != null);  //true
        System.out.println(myObject != null); //true

        return "data";
    }
}

但泽西没有把它注入我的过滤器:

public final class MyFilter implements ResourceFilter {

    @Context private HttpServletRequest request;
    @Context private MyObject myObject;

    @Override
    public ContainerRequestFilter getRequestFilter() {
        return new ContainerRequestFilter() {
            @Override
            public ContainerRequest filter(ContainerRequest containerRequest) {

                System.out.println(request != null);  //true
                System.out.println(myObject != null); //false

                return containerRequest;
            }
        };
    }

    @Override
    public ContainerResponseFilter getResponseFilter() {
        return null;
    }
}

我猜测差异与以下事实有关:MyFilter注入是使用遵循线程局部实例的代理完成的 - 这是因为声明了注释为@Context的字段在外部类中,它被实例化一次,但它们用于在每个请求的基础上注入对象。当我在调试期间单步执行filter时,我可以看到MyFilter.request指向包含com.sun.jersey.server.impl.container.servlet.ThreadLocalInvoker实例的代理。

我的自定义提供程序(或其他实现)缺少它需要在我的过滤器中自定义注入?

请注意,我目前仍然坚持使用Jersey 1.1.4.1(对不起)。

编辑:使用Jersey 1.17,我在启动时遇到异常:

  

严重:缺少字段依赖:private mypackage.MyObject mypackage.MyFilter.myObject

2 个答案:

答案 0 :(得分:1)

我使用Providers中的JSR-311可注射接口找到了解决方法。首先,我必须使我的提供者实现ContextResolver

@Provider
public final class MyProvider
extends AbstractHttpContextInjectable<MyObject>
implements InjectableProvider<Context, Type>, ContextResolver<MyObject> {

    ...

    @Override
    public MyObject getContext(Class<?> type) {
        //in reality, using the same logic as before
        return new MyObject();
    }
}

然后我将Providers实例注入了我的过滤器。调用filter后,我会使用它来查找ContextResolver MyObject并动态检索它:

public final class MyFilter implements ResourceFilter {

    @Context private HttpServletRequest request;
    @Context private Providers providers;

    @Override
    public ContainerRequestFilter getRequestFilter() {
        return new ContainerRequestFilter() {
            @Override
            public ContainerRequest filter(ContainerRequest containerRequest) {

                final ContextResolver<MyObject> myObjectResolver =
                            providers.getContextResolver(MyObject.class, null);
                final MyObject myObject =
                            myObjectResolver.getContext(MyObject.class);

                System.out.println(request != null);  //true
                System.out.println(myObject != null); //true

                return containerRequest;
            }
        };
    }

    ...
}

信用转到this answer,因为Providers引发了我的注意。解决方案有效,但它不是一个漂亮的解决方案。我仍然想在任何地方注入MyObject并让它工作,例如HttpServletRequest - 我想知道我的提供者缺少它需要实现的目的。

答案 1 :(得分:1)

我遇到了这个问题,尝试实现相同的目标(即注入自定义提供程序实现提供的内容),并发现如果您通过过滤器工厂进行自定义注入很有效。

因此,不要将@Context MyClass myObj注释放入Filter类,而是在负责创建过滤器的过滤器工厂中放置该类型的带注释字段,并让工厂将“myObj”作为常规参数传递。

我不确定这会对你的情况有所帮助,而且我没有调查过使用每个请求提供程序的意义(我的是单例范围的),所以YMMV。