2013-05-07 3 views
5

ジャージーの注射機構を理解するのは難しいです。 JAX-RS仕様書(http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-520005)では、アプリケーションサブクラス、ルートリソースクラス、およびプロバイダで@Context経由の注入が可能であると記載されています。ジャージー@Contextスコープ

私は、起動時にインスタンス化され、すべての要求に対して呼び出されるメソッドを持つクラスを持つようになりました。メソッドの中で、現在のUriInfoオブジェクトにアクセスする必要があります。問題は、このメソッドが自分のコードから呼び出されないということです。だから、UriInfoをメソッドに直接渡すことはできません。

は、私が実際にこのような何かをしたい:

public class MyClass implements ThirdPartyInterface { 

    // not possible because class is no Application subclass, root resource class or provider 
    @Context 
    private UriInfo uriInfo; 

    public void methodCallebByThirdPartyCode() { 
     Uri requestUri = uriInfo.getRequestUri(); 

     // do something 
    } 
} 

が、私はこれを試してみました。明らかに成功なし:

public class MyClass implements ThirdPartyInterface { 

    private UriInfo uriInfo; 

    public MyClass(UriInfo uriInfo) { 
     this.uriInfo = uriInfo; 
    } 

    public void methodCallebByThirdPartyCode() { 
     Uri requestUri = uriInfo.getRequestUri(); 

     // do something 
    } 
} 

@Provider 
@Produces(MediaType.WILDCARD) 
public class MyBodyWriter implements MessageBodyWriter<MyView> { 

    @Context 
    private UriInfo uriInfo; 

    private MyClass myClass; 

    private ThirdPartyClass thirdPartyClass; 

    public MyBodyWriter() { 
     // uriInfo is null at this time :(
     myClass = new MyClass(uriInfo); 

     thirdPartyClass = new ThirdPartyClass(); 
     thirdPartyClass.register(myClass); 
    } 

    public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException { 
     // execute() calls MyClass#methodCallebByThirdPartyCode() 
     thirdPartyClass.execute(); 
    } 
} 

これは私が考えることができる唯一の回避策です。私はそれが非常にきれいだとは思わない:

public class MyClass implements ThirdPartyInterface { 

    private UriInfo uriInfo; 

    public void setUriInfo(final UriInfo uriInfo) { 
     this.uriInfo = uriInfo; 
    } 

    public void methodCallebByThirdPartyCode() { 
     Uri requestUri = uriInfo.getRequestUri(); 

     // do something 
    } 
} 

@Provider 
@Produces(MediaType.WILDCARD) 
public class MyBodyWriter implements MessageBodyWriter<MyView> { 

    @Context 
    private UriInfo uriInfo; 

    private MyClass myClass; 

    private ThirdPartyClass thirdPartyClass; 

    public MyBodyWriter() { 
     myClass = new MyClass(); 

     thirdPartyClass = new ThirdPartyClass(); 
     thirdPartyClass.register(myClass); 
    } 

    public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException { 
     myClass.setUriInfo(uriInfo); 

     // execute() calls MyClass#methodCallebByThirdPartyCode() 
     thirdPartyClass.execute(); 

     myClass.setUriInfo(null); 
    } 
} 

私はそこに良い解決策があると思うが、多分私は間違ったトラックにいる。

ありがとうございます!あなたは注射用org.glassfish.hk2.api.Factoryjavax.inject.Providerを使用することができます

+0

「ContainerRequestFilter'が必要なのでしょうか? – Willy

+0

私の状況でこれが機能するかどうかわかりません。この仕様では、「プロバイダクラスはJAX-RSランタイムによってインスタンス化されています」と記載されています。しかし、私は建設時にオブジェクトを参照して、それを第三者のサービスに渡す必要があります。 –

答えて

3

後期の答えが、良い質問は...ので、行くことができます。私はこのバージョンが利用可能なので知らないので、あなたのjerseryバージョンをアップグレードする必要があります。以下のサンプルでは、​​jersey 2.12を使用しました。

まずあなたが実装し、登録/ごMyClassのための工場をバインドする必要があります。

MyClassFactory:

import javax.inject.Inject; 
import javax.ws.rs.core.UriInfo; 
import org.glassfish.hk2.api.Factory; 
// ... 

public class MyClassFactory implements Factory<MyClass> { 

    private final UriInfo uriInfo; 

    // we will bind MyClassFactory per lookup later, so 
    // the constructor will be called everytime we need the factory 
    // meaning, uriInfo is also per lookup 

    @Inject 
    public MyClassFactory(final UriInfo uriInfo) { 
     this.uriInfo = uriInfo; 
    } 

    @Override 
    public MyClass provide() { 
     return new MyClass(uriInfo) 
    } 

    @Override 
    public void dispose(UriInfo uriInfo) { 
     // ignore 
    } 

} 

ResourceConfigのを経由して登録:

import org.glassfish.hk2.api.PerLookup; 
import org.glassfish.hk2.utilities.binding.AbstractBinder; 
import org.glassfish.jersey.server.ResourceConfig; 
// ... 

public class MyResourceConfig extends ResourceConfig { 

    public MyResourceConfig() { 
     register(new AbstractBinder() { 
      @Override 
      protected void configure() { 
       bindFactory(MyClassFactory.class).to(MyClass.class).in(PerLookup.class); 
       // ... bind additional factories here 
      } 
     }); 
     // ... 
    } 

} 

を今、あなたはMyClassのを注入することができますプロバイダ、リソースなどにルックアップごとに
注意:Afaigには2つのアプローチがありますESと一つだけが、これは何とか参考になった

import javax.inject.Inject; 
import javax.ws.rs.Produces; 
import javax.ws.rs.ext.MessageBodyWriter; 
import javax.ws.rs.ext.Provider; 
// ... 

@Provider 
@Produces("application/foo-bar") 
public class MyBodyWriter implements MessageBodyWriter<MyView> { 

    // first approache - don't do it! 
    // will only injected once, cause MyBodyWriter is only instantiated once 
    @Inject 
    private MyClass myClass; 

    // second approache - works fine! 
    private final javax.inject.Provider<MyClass> provider; 

    // MyBodyWriter instantiate once 
    // get an inject provider here 
    @Inject 
    public MyBodyWriter(javax.inject.Provider<MyClass> myClassProvider) { 
     this.provider = myClassProvider; 
    } 

    @Override 
    public boolean isWriteable(Class<?> t, Type g, Annotation[] a, MediaType m) { 
     return t == MyView.class; 
    } 

    @Override 
    public long getSize(MyView t, Class<?> c, Type g, Annotation[] a, MediaType m) { 
     // deprecated by JAX-RS 2.0 and ignored by Jersey runtime 
     return 0; 
    } 

    @Override 
    public void writeTo(MyView v, Class<?> c, Type t, Annotation[] a, MediaType m, MultivaluedMap<String, Object> s, OutputStream o) throws IOException, WebApplicationException { 

     // attention: its not per lookup !!! 
     MyClass myClassDirectInjected = myClass; 
     System.out.println(myClassDirectInjected); // same instance everytime 

     // but this is ;) 
     MyClass myClassFromProvider = provider.get(); 
     System.out.println(myClassFromProvider); // it's a new instance everytime 

     // ... 
    } 

} 

希望...など、最終的にプロバイダのaspected動作します。

関連する問題