これは、なにをしたくて書いたもの?
RESTEasy 6.1.0に関するブログを見ていて、JAX-RS(Jakarta RESTful Web Services)のインジェクションの仕組みはCDIの利用が
推奨されるようになっていたので、こちらを軽く確認しておきました。
JAX-RS 3.1.0で@Contextが非推奨になり、CDIの利用が推奨に
RESTEasy 6.1.0.Finalのリリースに関するブログエントリーを見ると、以下のように書かれていました。
In Jakarta REST 3.1 the @Context is deprecated. While @Context is still currently supported, future versions may remove support.
@Context
は非推奨になり、将来的には削除されるようですね。
JAX-RS 3.1.0の仕様の方を見ると、@Context
と@ContextResolver
は将来的にはサポートされなくなり、CDIを使うようになっていく
みたいです。
As part of an effort to better align with Jakarta CDI, future versions of this API will no longer support @Context injection and related types such as ContextResolver. As much as possible, all injection tasks will be delegated to Jakarta CDI for a better integration into the Jakarta EE ecosystem.
Jakarta RESTful Web Services 3.1.0 / Introduction / Status / Support for @Context Injection
@Context
のJavadocを見ると、@deprecated
とまではなっていないものの、将来的にはサポートが停止されることは書かれています。
Note that future versions of this API will stop supporting injection via Context as part of a tighter integration and alignment with Jakarta CDI.
Context (Jakarta EE Platform API)
ContextResolver
の方には、特になにも書かれていません。
ContextResolver (Jakarta EE Platform API)
話を戻して。
RESTEasy 6.1.0では、以下の要素がCDI管理Beanとしてインジェクション可能になっているようです。
With this, RESTEasy has added some support for injecting the known types which @Context also injects. One note is this currently does not work with method parameter injection. The following types can be injected as global fields in CDI managed beans.
- ApplicationScoped
- jakarta.ws.rs.core.Configuration
- jakarta.ws.rs.ext.Providers
- jakarta.ws.rs.core.Application
- jakarta.ws.rs.client.Client
- jakarta.ws.rs.container.ResourceContext
- jakarta.ws.rs.container.ResourceInfo
- RESTEasy 6.2.0.Finalで追加
- jakarta.ws.rs.core.SecurityContext
- jakarta.ws.rs.sse.Sse
- jakarta.ws.rs.core.UriInfo
- RequestScoped
※) ブログエントリーの情報に、スコープやRESTEasy 6.2.0.Finalでの追加要素を入れています
注意点としては、@Context
の時とは違ってメソッドの引数としてのインジェクションはできません。
今回、こちらの一部を簡単に確認しておきましょう。
環境
今回の環境は、こちら。
$ java --version openjdk 17.0.5 2022-10-18 OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04) OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing) $ mvn --version Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 17.0.5, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-135-generic", arch: "amd64", family: "unix"
確認には、WildFly 27.0.1.Finalを使います。
$ bin/standalone.sh --version ========================================================================= JBoss Bootstrap Environment JBOSS_HOME: /path/to/wildfly-27.0.1.Final JAVA: /usr/lib/jvm/default/bin/java JAVA_OPTS: -server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Djava.security.manager=allow ========================================================================= 19:31:48,663 INFO [org.jboss.modules] (main) JBoss Modules version 2.0.3.Final WildFly Full 27.0.1.Final (WildFly Core 19.0.1.Final)
起動。
$ bin/standalone.sh
WildFly 27.0.1.Finalに含まれているRESTEasyは6.2.1.Finalであり、JAX-RS(Jakarta RESTful Web Services) 3.1.0の実装なので今回は
RESTEasy 6.2.1.Finalの情報で見ていきます。
JAX-RSを使ったアプリケーションを作成する
では、JAX-RSを使ったアプリケーションを作成していきます。
pom.xml
から。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.littlewings</groupId> <artifactId>resteasy-cdi-injection</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-web-api</artifactId> <version>10.0.0</version> </dependency> </dependencies> <build> <finalName>ROOT</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </plugin> </plugins> </build> </project>
JAX-RSの有効化。
src/main/java/org/littlewings/jaxrs/cdi/JaxrsActivator.java
package org.littlewings.jaxrs.cdi; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("") public class JaxrsActivator extends Application { }
JAX-RSリソースクラス。
src/main/java/org/littlewings/jaxrs/cdi/SampleResource.java
package org.littlewings.jaxrs.cdi; import java.util.Map; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.UriInfo; @Path("sample") @ApplicationScoped // あってもなくても動く public class SampleResource { @Inject UriInfo uriInfo; @Inject Client client; @GET @Path("uriInfo1") @Produces(MediaType.APPLICATION_JSON) public Map<String, String> uriInfo1() { return Map.of( "getAbsolutePath", uriInfo.getAbsolutePath().toASCIIString(), "getBaseUri", uriInfo.getBaseUri().toASCIIString(), "getRequestUri", uriInfo.getRequestUri().toASCIIString(), "getPath", uriInfo.getPath(), "getQueryParameters", uriInfo.getQueryParameters().toString() ); } @GET @Path("uriInfo2") @Produces(MediaType.APPLICATION_JSON) public Map<String, String> uriInfo2() { return Map.of( "getAbsolutePath", uriInfo.getAbsolutePath().toASCIIString(), "getBaseUri", uriInfo.getBaseUri().toASCIIString(), "getRequestUri", uriInfo.getRequestUri().toASCIIString(), "getPath", uriInfo.getPath(), "getQueryParameters", uriInfo.getQueryParameters().toString() ); } @GET @Path("google") @Produces(MediaType.TEXT_PLAIN) public String google() { return client .target("https://www.google.co.jp/") .request() .get(String.class); } }
すでに使っていますが、こんな感じでJAX-RSのインターフェースをCDIでインジェクションできます。
@Inject UriInfo uriInfo; @Inject Client client;
今回はUriInfo
でアクセスされた時の情報をメソッド別に見たり、Client
を使ってGoogleにアクセスしたりしてみます。
パッケージングして
$ mvn package
WildFlyにデプロイ。
$ cp target/ROOT.war /path/to/wildfly-27.0.1.Final/standalone/deployments
確認してみます。
UriInfo
。
$ curl -s localhost:8080/sample/uriInfo1?foo=bar | jq { "getRequestUri": "http://localhost:8080/sample/uriInfo1?foo=bar", "getPath": "/sample/uriInfo1", "getAbsolutePath": "http://localhost:8080/sample/uriInfo1", "getBaseUri": "http://localhost:8080/", "getQueryParameters": "{foo=[bar]}" } $ curl -s localhost:8080/sample/uriInfo2?hoge=fuga | jq { "getRequestUri": "http://localhost:8080/sample/uriInfo2?hoge=fuga", "getPath": "/sample/uriInfo2", "getAbsolutePath": "http://localhost:8080/sample/uriInfo2", "getBaseUri": "http://localhost:8080/", "getQueryParameters": "{hoge=[fuga]}" }
Client
。
$ curl -s localhost:8080/sample/google <!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能 を活用して、お探しの情報を見つけてください。" name="description"> 〜省略〜
OKですね。
各インターフェースがCDI管理Beanとして登録されている箇所は?
最後に、実装を見ていきましょう。
RESTEasyのどこで各インターフェースがCDI管理Beanとして登録されているか、確認してみます。
ほとんどのクラスは、以下のクラスで@Produces
を使ってCDI管理Beanとして登録されています。
Client
だけは、こちらで登録されているようです。
まとめ
JAX-RS 3.1.0で、インジェクションでは@Context
アノテーションではなくCDIを使うように勧められていたので、簡単に試してみました。