Jersey 2.0での依存性注入


108

以前のJersey 1.xの知識がない状態でゼロから始めて、私はJersey 2.0プロジェクトで依存関係注入をセットアップする方法を理解するのに苦労しています。

また、HK2がJersey 2.0で利用可能であることも理解していますが、Jersey 2.0の統合に役立つドキュメントを見つけることができないようです。

@ManagedBean
@Path("myresource")
public class MyResource {

    @Inject
    MyService myService;

    /**
     * Method handling HTTP GET requests. The returned object will be sent
     * to the client as "text/plain" media type.
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/getit")
    public String getIt() {
        return "Got it {" + myService + "}";
    }
}

@Resource
@ManagedBean
public class MyService {
    void serviceCall() {
        System.out.print("Service calls");
    }
}

pom.xml

<properties>
    <jersey.version>2.0-rc1</jersey.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey</groupId>
        <artifactId>jax-rs-ri</artifactId>
    </dependency>
</dependencies>

コンテナーを起動してリソースを提供することはできますが、@ InjectをMyServiceに追加するとすぐに、フレームワークが例外をスローします。

SEVERE: Servlet.service() for servlet [com.noip.MyApplication] in context with path [/jaxrs] threw exception [A MultiException has 3 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.noip.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.noip.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128)
    at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)


私のスタータープロジェクトはGitHubで入手できます:https : //github.com/donaldjarmstrong/jaxrs

回答:


107

を定義AbstractBinderしてJAX-RSアプリケーションに登録する必要があります。バインダーは、依存性注入がクラスを作成する方法を指定します。

public class MyApplicationBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(MyService.class).to(MyService.class);
    }
}

場合@Inject種類のパラメータまたはフィールド上で検出されMyService.class、それは、クラスを使用してインスタンス化されますMyService。このバインダーを使用するには、JAX-RSアプリケーションに登録する必要があります。でweb.xml、次のようにJAX-RSアプリケーションを定義します。

<servlet>
  <servlet-name>MyApplication</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>com.mypackage.MyApplication</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>MyApplication</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

MyApplicationクラスを実装します(上記で指定init-param)。

public class MyApplication extends ResourceConfig {
    public MyApplication() {
        register(new MyApplicationBinder());
        packages(true, "com.mypackage.rest");
    }
}

依存性注入を指定するバインダーは、クラスのコンストラクターに登録されています。またMyResourcepackages()メソッド呼び出しを使用して、RESTリソースの場所(あなたの場合)をアプリケーションに通知します。


1
EntityManagerはどうですか?バインドするためのヒントはありますので、@ PersistenceContextを介して挿入できますか?
Johannes Staehlin 2013年

4
何なのかEntityManagerわかりませんが、docs.oracle.com / javaee / 6 / api / javax / persistence /から判断すると、インターフェースのようです。を使用してバインドできますbind(EntityManagerImpl.class).to(EntityManager.class)(これEntityManagerImplにより、インターフェイスを実装するクラスがバインドされますEntityManager。ファクトリを使用する必要がある場合は、を参照しbindFactory()AbstractBinderください。これについてサポートが必要な場合は、新しい質問を作成してください(私にはスペースがありませんコメントでそれを答えてください)また、
@ PersistentContextを

ええ、EntityManagerはJPA(Java EE)固有です。コメントありがとうございます。特定の問題が発生した場合は、別の質問を開きます!
Johannes Staehlin 2013年

参考までに、JPAはJava SEでも動作します。oracle.com/technetwork/java/javaee/tech/...
prefabSOFT

2
bindは何をしますか?インターフェイスと実装がある場合はどうなりますか?
Dejell 2014年

52

まず、受諾回答のコメントに回答するだけです。

「バインドは何をしますか?インターフェイスと実装がある場合はどうなりますか?」

それは単に読みますbind( implementation ).to( contract )。代替チェーンができ.in( scope )ます。のデフォルトのスコープPerLookup。シングルトンが必要な場合は、

bind( implementation ).to( contract ).in( Singleton.class );

もあります RequestScoped利用可能なます

また、の代わりにbind(Class).to(Class)を使用することもできますbind(Instance).to(Class)。これは自動的にシングルトンになります。


受け入れられた回答に追加する

AbstractBinderweb.xmlに実装を登録する方法を理解しようとしている(つまりResourceConfig、を使用していない)場合、パッケージスキャンによってバインダーが検出されないようです。

<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
    <param-name>jersey.config.server.provider.packages</param-name>
    <param-value>
        your.packages.to.scan
    </param-value>
</init-param>

またはこれ

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>
        com.foo.YourBinderImpl
    </param-value>
</init-param>

それを機能させるために、私は実装する必要がありました Feature

import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;

@Provider
public class Hk2Feature implements Feature {

    @Override
    public boolean configure(FeatureContext context) {
        context.register(new AppBinder());
        return true;
    }
}

@Provider注釈は許可する必要がありFeature、パッケージスキャンによってピックアップされます。または、パッケージスキャンなしFeatureで、明示的にweb.xml

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>
            com.foo.Hk2Feature
        </param-value>
    </init-param>
    ...
    <load-on-startup>1</load-on-startup>
</servlet>

関連項目:

ジャージーのドキュメントからの一般的な情報


更新

工場

受け入れられた回答の基本的なバインディングの他に、より複雑な作成ロジックを持つことができるファクトリーもあり、コンテキスト情報の要求にアクセスすることもできます。例えば

public class MyServiceFactory implements Factory<MyService> {
    @Context
    private HttpHeaders headers;

    @Override
    public MyService provide() {
        return new MyService(headers.getHeaderString("X-Header"));
    }

    @Override
    public void dispose(MyService service) { /* noop */ }
}

register(new AbstractBinder() {
    @Override
    public void configure() {
        bindFactory(MyServiceFactory.class).to(MyService.class)
                .in(RequestScoped.class);
    }
});

次にMyService、リソースクラスに注入できます。


受け入れられた回答に示されているように、ResourceConfig実装を介してバインダークラスを登録できます。フィーチャクラスは必要ありませんでした。
Patrick Koorevaar

使用しweb.xmlていてもconfigure()上がHk2Feature呼ばれて、リソースを要求することはスローNullPointerException。@PaulSamsotha
bytesandcaffeine

12

選択された回答は、さかのぼって遡ります。カスタムHK2バインダーですべてのバインディングを宣言することは現実的ではありません。私はTomcatを使用しており、依存関係を1つ追加するだけで済みました。Glassfish用に設計されていますが、他のコンテナに完全に適合します。

   <dependency>
        <groupId>org.glassfish.jersey.containers.glassfish</groupId>
        <artifactId>jersey-gf-cdi</artifactId>
        <version>${jersey.version}</version>
    </dependency>

コンテナも適切に構成されていることを確認してください(ドキュメントを参照)。


最後の行(コンテナーも適切に構成されていることを確認してください)は少しあいまいです。ここで何か助けはありますか?どのアノテーションをどこで使用しますか?
markthegrea 2016年

私たちは依存関係の注入にWeldを使用していましたが、Tomcat(アプリケーション「コンテナー」)と連携するために特別な構成が必要でした。Springを使用している場合は、そのまま使用できます。
otonglet 2016

5

遅いですが、これが誰かを助けることを願っています。

私はJAX RSを次のように定義しています。

@Path("/examplepath")
@RequestScoped //this make the diference
public class ExampleResource {

次に、私のコードで最後に注入できます:

@Inject
SomeManagedBean bean;

私の場合、 SomeManagedBeanはApplicationScoped Beanです。

これが誰にも役立つことを願っています。


3

Oracleは、CDIとJAX-RSを組み合わせる際に注入されるすべてのタイプに@Pathアノテーションを追加することをお勧めします。 http://docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm ここまで完璧からですが(たとえば、起動時にJerseyから警告が表示されます)、私はこの方法を採用することにしました。これにより、バインダー内でサポートされているすべてのタイプを維持する必要がなくなります。

例:

@Singleton
@Path("singleton-configuration-service")
public class ConfigurationService {
  .. 
}

@Path("my-path")
class MyProvider {
  @Inject ConfigurationService _configuration;

  @GET
  public Object get() {..}
}

1
リンクは死んでいる、ここ
ハンク


0

私にとってAbstractBinderは、Webアプリケーション(Tomcat 8.5、Jersey 2.27で実行)に次の依存関係を含めれば、問題なく動作します。

<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>${jersey-version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.ext.cdi</groupId>
    <artifactId>jersey-cdi1x</artifactId>
    <version>${jersey-version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>${jersey-version}</version>
</dependency>

CDI 1.2 / CDI 2.0で動作します(それぞれWeld 2/3を使用)。


0

jersey RESTfulサービスとTomcatがサーバーに必要な依存関係。ここで、$ {jersey.version}は2.29.1です

    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>2.0.SP1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>${jersey.version}</version>
    </dependency>

基本的なコードは次のようになります。

@RequestScoped
@Path("test")
public class RESTEndpoint {

   @GET
   public String getMessage() {
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.