このシナリオでは、フィルターを記述し、このフィルターでオブジェクトを現在の要求に挿入して渡すことで、リソースクラスが要求を取得したときにオブジェクトを使用できるようにします。
フィルタークラス
@Override
public void filter(ContainerRequestContext request) throws IOException {
MyObject obj = new MyObject();
// Inject MyObject to request which I dont know how
}
リソースクラス
@PUT @Consumes("application/json")
@Path("/")
public String create(
JSONParam sample,
@Context MyObject obj) {
System.out.println(obj.getName());
return "";
}
単にContainterRequestContext.setProperty(String, Object)
を使用できます。次に、ContainerRequestContext
を挿入するだけです
@Override
public void filter(ContainerRequestContext crc) throws IOException {
MyObject obj = new MyObject();
crc.setProperty("myObject", myObject);
}
@POST
public Response getResponse(@Context ContainerRequestContext crc) {
return Response.ok(crc.getProperty("myObject")).build();
}
MyObject
を直接注入する別のオプションは、Jersey 2が提供するHK2機能を使用することです。
ContainerRequestContext
を挿入してMyObject
を返すファクトリを作成します。例えば
import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
import jetty.plugin.test.domain.MyObject;
import org.glassfish.hk2.api.Factory;
public class MyObjectFactory implements Factory<MyObject> {
private final ContainerRequestContext context;
@Inject
public MyObjectFactory(ContainerRequestContext context) {
this.context = context;
}
@Override
public MyObject provide() {
return (MyObject)context.getProperty("myObject");
}
@Override
public void dispose(MyObject t) {}
}
次に、ファクトリをバインドする必要があります。
public class InjectApplication extends ResourceConfig {
public InjectApplication() {
...
register(new AbstractBinder(){
@Override
protected void configure() {
bindFactory(MyObjectFactory.class)
.to(MyObject.class)
.in(RequestScoped.class);
}
});
}
}
上記のフィルター例と同じプロパティの設定で、MyObject
に@Context
@GET
public Response getTest(@Context MyObject myObject) {
return Response.ok(myObject.getMessage()).build();
}
Custom Injection
この実装の問題については、 この質問 をご覧ください。
関連項目:
DIコンテナを必要としない、これに対する解決策がありますが、それでもほとんどの利点が得られます。
2つの部分があります。 1つ目は、ApplicationConfigオブジェクトでクラスを提供する代わりに、@ Contextインジェクションメカニズムにインスタンスを取得する方法です。
これを行うための手法を次に示します。
private static class CustomContextResteasyBootstrap extends org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap{
private final Map<Class<?>, Object> additionalContextObjects = new HashMap<Class<?>, Object>();
public <E> CustomContextResteasyBootstrap addContextObject(Class<? super E> clazz, E obj){
additionalContextObjects.put(clazz, obj);
return this;
}
@Override
public void contextInitialized(ServletContextEvent event) {
super.contextInitialized(event);
deployment.getDispatcher().getDefaultContextObjects().putAll(additionalContextObjects);
}
}
次のように使用します:
webAppContext.addEventListener(
new CustomContextResteasyBootstrap()
.addContextObject(MyCustom.class, myCustom)
.addContextObject(AnotherCustom.class, anotherCustom)
// additional objects you wish to inject into the REST context here
);
@Contextアノテーションでこれらのクラスを使用できるようになりました。
@GET
public MyCustom echoService(@Context MyCustom custom) {
return custom;
}
パズルの次の部分は、リクエストごとのコンテキストオブジェクトを提供する方法です。これを行うには、jax-rs呼び出し階層の最上部付近に次のコードを追加します(基本的に、この行の下で呼び出されるものはすべてコンテキストオブジェクトにアクセスできます)。
ResteasyProviderFactory.pushContext(MyContextSpecific.class, new MyContextSpecific());
次に、そのレベルより下の任意の場所でインジェクションを介してこれを参照できます。
@GET
public String contextSpecificEchoService(@Context MyContextSpecific contextSpecific) {
return custom.toString();
}
これは貧乏人のDIですが、組み込みのレストサーバーでは非常にうまく機能します。