当@Context用于setter / field / constructor注入时,HK2 Factory在Jerseyfilter之前调用

我已经能够根据如何将对象注入到jersey请求上下文中从filter注入我的jersey资源? 。 这允许我成功注入方法参数:

@GET public Response getTest(@Context MyObject myObject) { // this works 

但是,对于setter / field / constructor注入,HK2 Factory在jerseyfilter之前调用,这意味着provide()方法返回null:

 @Override public MyObject provide() { // returns null because the filter has not yet run, // and the property has not yet been set return (MyObject)context.getProperty("myObject"); } 

有没有办法定义何时运行HK2 Factory以便在filter运行调用它? 如果没有,则解决方法是将MyObject定义为接口,并定义在其构造函数中采用ContainerRequestContext的其他实现; 任何实际使用该实例的尝试都将懒惰地委托给在ContainerRequestContext属性上设置的实现(可能在filter运行之前你不会实际使用该实例 – 此时将设置该属性)。

但我想了解是否有可能延迟HK2工厂运行的点,使其在filter之后运行(在方法参数注入的情况下,它已在filter之后运行)。 如果不可能,那么我想了解是否存在根本原因。

奇怪的是,它只适用于我在filter上使用@PreMatching (这限制了对您可能需要或可能不需要的某些内容的访问)。 不太确定引擎盖下发生了什么,如果没有它就不能工作:-(。以下是使用Jersey Test Framework的完整测试。

 import java.io.IOException; import javax.inject.Inject; import javax.inject.Singleton; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.core.Application; import javax.ws.rs.core.Context; import javax.ws.rs.ext.Provider; import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.jersey.process.internal.RequestScoped; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory; import org.glassfish.jersey.test.JerseyTest; import org.junit.Assert; import org.junit.Test; public class FilterInjectionTest extends JerseyTest { private static final String MESSAGE = "Inject OK"; private static final String OBJ_PROP = "myObject"; public static class MyObject { private final String value; public MyObject(String value) { this.value = value; } public String getValue() { return value; } } @PreMatching @Provider public static class MyObjectFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext context) throws IOException { MyObject obj = new MyObject(MESSAGE); context.setProperty(OBJ_PROP, obj); } } public static class MyObjectFactory extends AbstractContainerRequestValueFactory { @Override @RequestScoped public MyObject provide() { return (MyObject) getContainerRequest().getProperty(OBJ_PROP); } @Override public void dispose(MyObject t) { } } @Path("method-param") public static class MethodParamResource { @GET public String getResponse(@Context MyObject myObject) { return myObject.getValue(); } } @Path("constructor") public static class ConstructorResource { private final MyObject myObject; @Inject public ConstructorResource(@Context MyObject myObject) { this.myObject = myObject; } @GET public String getResponse() { return myObject.getValue(); } } @Path("field") public static class FieldResource { @Inject private MyObject myObject; @GET public String getResponse() { return myObject.getValue(); } } @Override public Application configure() { ResourceConfig config = new ResourceConfig(); config.register(MethodParamResource.class); config.register(MyObjectFilter.class); config.register(ConstructorResource.class); config.register(FieldResource.class); config.register(new AbstractBinder() { @Override protected void configure() { bindFactory(MyObjectFactory.class) .to(MyObject.class).in(Singleton.class); } }); return config; } @Test public void methoParamInjectionOk() { String response = target("method-param").request().get(String.class); Assert.assertEquals(MESSAGE, response); System.out.println(response); } @Test public void costructorInjectionOk() { String response = target("constructor").request().get(String.class); Assert.assertEquals(MESSAGE, response); System.out.println(response); } @Test public void fieldInjectionOk() { String response = target("field").request().get(String.class); Assert.assertEquals(MESSAGE, response); System.out.println(response); } } 

UPDATE

解决方案,无需使其成为@PreMatchingfilter,是使用javax.inject.Provider注入。 这将允许您懒惰地检索对象。 我想构造函数和字段注入会在匹配资源类之后发生,它会立即创建并注入。 由于尚未调用filter,因此工厂没有对象。 它适用于方法注入,因为它就像任何其他方法调用一样。 调用该方法时,该对象将传递给它。 下面是javax.inject.Provider的示例

 @Path("constructor") public static class ConstructorResource { private final javax.inject.Provider myObjectProvider; @Inject public ConstructorResource(javax.inject.Provider myObjectProvider) { this.myObjectProvider = myObjectProvider; } @GET public String getResponse() { return myObjectProvider.get().getValue(); } } @Path("field") public static class FieldResource { @Inject private javax.inject.Provider myObjectProvider;; @GET public String getResponse() { return myObjectProvider.get().getValue(); } }