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
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");
}
}
依存性注入を指定するバインダーは、クラスのコンストラクターに登録されます。また、packages()
を使用して、RESTリソース(場合によってはMyResource
)を見つける場所をアプリケーションに伝えます。メソッド呼び出し。
最初に、accepts回答のコメントに回答します。
「バインドとは何ですか?インターフェイスと実装がある場合はどうなりますか?」
単にbind( implementation ).to( contract )
を読み取ります。チェーン.in( scope )
を代替できます。 PerLookup
のデフォルトスコープ。したがって、シングルトンが必要な場合は、次のことができます
bind( implementation ).to( contract ).in( Singleton.class );
RequestScoped
も利用可能です
また、bind(Class).to(Class)
の代わりに、自動的にシングルトンになるbind(Instance).to(Class)
を使用することもできます。
受け入れられた答え に追加する
AbstractBinder
実装をweb.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
がパッケージスキャンによって取得されることを許可する必要があります。または、パッケージをスキャンせずに、web.xml
にFeature
を明示的に登録できます
<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>
関連項目:
jerseyのドキュメントの一般情報
受け入れられた答えの基本的なバインディングとは別に、より複雑な作成ロジックを持つことができるファクトリーがあり、コンテキスト情報を要求するためのアクセス権も持っています。例えば
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
をリソースクラスに注入できます。
選択された回答はしばらく前の日付です。カスタムHK2バインダーですべてのバインディングを宣言することは実用的ではありません。 Tomcatを使用していますが、1つの依存関係を追加する必要がありました。 Glassfish用に設計されていても、他のコンテナに完全に収まります。
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>${jersey.version}</version>
</dependency>
コンテナも適切に設定されていることを確認してください( ドキュメントを参照 )。
遅いですが、これが誰かの助けになることを願っています。
私のJAX RSは次のように定義されています:
@Path("/examplepath")
@RequestScoped //this make the diference
public class ExampleResource {
その後、私のコードで最終的に注入することができます:
@Inject
SomeManagedBean bean;
私の場合、SomeManagedBean
はApplicationScoped Beanです。
これが誰にも役立つことを願っています。
JAX-RSとCDIを組み合わせる場合、挿入するすべてのタイプに@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() {..}
}
私にとって、Webアプリケーションに次の依存関係を含めると、AbstractBinder
がなくても動作します(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を使用)。
Guiceの使用を希望し、すべてのバインディングを宣言したくない場合は、このアダプターを試すこともできます。