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