4

我有一个 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

4

2 回答 2

1

我找到了使用JSR-311Providers中的可注入接口的解决方法。首先,我必须让我的提供者实现: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被调用时,我使用它来查找ContextResolverforMyObject并动态检索它:

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

    ...
}

归功于这个答案,因为它给了我关于Providers. 该解决方案有效,但它不是一个漂亮的解决方案。我仍然想在MyObject任何地方注入并让它工作,就像HttpServletRequest- 我想知道我的提供者缺少什么来实现这一点。

于 2013-03-26T05:45:39.920 回答
1

我遇到了这个问题,试图实现相同的目标(即注入自定义 Provider 实现提供的东西),并发现如果您通过过滤器工厂进行自定义注入,效果很好。

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

我不确定这会对您的情况有所帮助,并且我还没有调查将其与每个请求提供程序一起使用的含义(我的是单例范围的),所以 YMMV。

于 2013-07-08T09:10:27.143 回答