これは、なにをしたくて書いたもの?
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を使うように勧められていたので、簡単に試してみました。