RESTEasy Classic
このガイドは、Quarkus 2.8 までデフォルトの Jakarta REST (旧称 JAX-RS) 実装であった RESTEasy Classic に関するものです。 現在は、従来のブロッキングワークロードとリアクティブワークロードの両方を同様にサポートする Quarkus REST (旧称 RESTEasy Reactive) の使用が推奨されています。 Quarkus REST の詳細は、REST JSON 入門ガイド または Quarkus REST リファレンスドキュメント を参照してください。 |
RESTEasy Classic をベースにした REST クライアント (JSON のサポートを含む) が必要な場合は、別のガイド を参照してください。 |
アーキテクチャ
このガイドで作成されるアプリケーションは簡単です。ユーザーがフォームを通じてリストに要素を追加でき、それに応じてリストが更新されます。
ブラウザとサーバー間の情報はすべてJSON形式になっています。
Maven プロジェクトの作成
最初に、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=rest-json-quickstart"
このコマンドは、RESTEasy/Jakarta REST および Jackson エクステンションをインポートする新しいプロジェクトを生成し、特に次の依存関係を追加します。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
implementation("io.quarkus:quarkus-resteasy-jackson")
ユーザーエクスペリエンスを向上させるために、Quarkus は 3 つの Jackson Java 8 モジュール を登録しているので、手動で登録する必要はありません。 |
Quarkus は JSON-B もサポートしているため、Jackson よりも JSON-B を利用したい場合は、代わりに RESTEasy JSON-B エクステンションを依存関係に持つプロジェクトを作成することができます。
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=rest-json-quickstart"
このコマンドは、RESTEasy/Jakarta REST および JSON-B エクステンションをインポートする新しいプロジェクトを生成し、特に次の依存関係を追加します。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
implementation("io.quarkus:quarkus-resteasy-jsonb")
初めての JSON REST サービスの作成
この例では、果物のリストを管理するアプリケーションを作成します。
まず、次のように Fruit
Bean を作成してみましょう。
package org.acme.rest.json;
public class Fruit {
public String name;
public String description;
public Fruit() {
}
public Fruit(String name, String description) {
this.name = name;
this.description = description;
}
}
派手なことは何もありません。注意すべき重要なことはJSONシリアライズレイヤーがデフォルトコンストラクターを必要とすることだけです。
次に、 org.acme.rest.json.FruitResource
クラスを以下のように作成します。
package org.acme.rest.json;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Set;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
@Path("/fruits")
public class FruitResource {
private Set<Fruit> fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));
public FruitResource() {
fruits.add(new Fruit("Apple", "Winter fruit"));
fruits.add(new Fruit("Pineapple", "Tropical fruit"));
}
@GET
public Set<Fruit> list() {
return fruits;
}
@POST
public Set<Fruit> add(Fruit fruit) {
fruits.add(fruit);
return fruits;
}
@DELETE
public Set<Fruit> delete(Fruit fruit) {
fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name));
return fruits;
}
}
実装は非常に簡単で、Jakarta RESTアノテーションを使用してエンドポイントを定義するだけです。
デフォルトの JSON 動作を無効にするには、 JSON のデフォルトに依存しない場合は、エンドポイントで |
JSON サポートの設定
Jackson
Quarkus では、CDI 経由で取得された (Quarkus エクステンションによって利用される) デフォルトの Jackson ObjectMapper
は、(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
を無効にして) 不明なプロパティーを無視するように設定されています。
Jackson のデフォルトの動作に戻すには、application.properties
で quarkus.jackson.fail-on-unknown-properties=true
を設定するか、@JsonIgnoreProperties(ignoreUnknown = false)
を使用してクラスごとに設定します。
さらに、ObjectMapper
は、(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
を無効にして) 日付と時刻を ISO-8601 でフォーマットします 。
Jackson のデフォルトの動作を復元するには、application.properties
で quarkus.jackson.write-dates-as-timestamps=true
を使用します。
単一フィールドのカスタム日付形式の場合は、@JsonFormat
アノテーションを使用します。
Quarkus は、CDI Bean を介して Jackson の設定を簡素化します。さまざまな Jackson 設定を適用するには、io.quarkus.jackson.ObjectMapperCustomizer
タイプの CDI Bean を作成します。カスタムモジュールを登録する例を次に示します。
@ApplicationScoped
public class MyObjectMapperCustomizer implements ObjectMapperCustomizer {
@Override
public void customize(ObjectMapper objectMapper) {
// Add custom Jackson configuration here
}
}
Jackson 設定を設定する場合は、このアプローチが推奨されます。
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;
@Singleton
public class RegisterCustomModuleCustomizer implements ObjectMapperCustomizer {
public void customize(ObjectMapper mapper) {
mapper.registerModule(new CustomModule());
}
}
ユーザーは、選択すれば自分の ObjectMapper
Bean を提供することもできます。この場合、 ObjectMapper
を生成する CDI プロデューサーの中で、すべての io.quarkus.jackson.ObjectMapperCustomizer
Bean を手動で注入して適用することが非常に重要です。これを怠ると、様々なエクステンションによって提供される Jackson 固有のカスタマイズが適用されなくなります。
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.arc.All;
import io.quarkus.jackson.ObjectMapperCustomizer;
import java.util.List;
import jakarta.inject.Singleton;
public class CustomObjectMapper {
// Replaces the CDI producer for ObjectMapper built into Quarkus
@Singleton
ObjectMapper objectMapper(@All List<ObjectMapperCustomizer> customizers) {
ObjectMapper mapper = myObjectMapper(); // Custom `ObjectMapper`
// Apply all ObjectMapperCustomizer beans (incl. Quarkus)
for (ObjectMapperCustomizer customizer : customizers) {
customizer.customize(mapper);
}
return mapper;
}
}
JSON-B
上記のように、 Quarkus では、 quarkus-resteasy-jsonb
エクステンションを使用することで、 Jackson の代わりに JSON-B を使用するオプションを提供しています。
前のセクションで説明したのと同じアプローチに従って、io.quarkus.jsonb.JsonbConfigCustomizer
Bean を使用して JSON-B を設定できます。
たとえば、 FooSerializer
という名前のカスタムシリアライザーを com.example.Foo
タイプで JSON-B で登録する必要がある場合、以下のような Bean を追加すれば十分です。
import io.quarkus.jsonb.JsonbConfigCustomizer;
import jakarta.inject.Singleton;
import jakarta.json.bind.JsonbConfig;
import jakarta.json.bind.serializer.JsonbSerializer;
@Singleton
public class FooSerializerRegistrationCustomizer implements JsonbConfigCustomizer {
public void customize(JsonbConfig config) {
config.withSerializers(new FooSerializer());
}
}
より高度なオプションは、jakarta.json.bind.JsonbConfig
の Bean を (Dependent
スコープで) 直接提供するか、極端な場合、jakarta.json.bind.Jsonb
タイプの Bean を (Singleton
スコープで) 提供することでしょう。
後者の方法を利用する場合、jakarta.json.bind.Jsonb
を生成する CDI プロデューサーにおいて、すべての io.quarkus.jsonb.JsonbConfigCustomizer
Bean を手動で注入し適用することが非常に重要です。
これを怠ると、さまざまなエクステンションが提供する JSON-B 固有のカスタマイズが適用されなくなります。
import io.quarkus.jsonb.JsonbConfigCustomizer;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.Instance;
import jakarta.json.bind.JsonbConfig;
public class CustomJsonbConfig {
// Replaces the CDI producer for JsonbConfig built into Quarkus
@Dependent
JsonbConfig jsonConfig(Instance<JsonbConfigCustomizer> customizers) {
JsonbConfig config = myJsonbConfig(); // Custom `JsonbConfig`
// Apply all JsonbConfigCustomizer beans (incl. Quarkus)
for (JsonbConfigCustomizer customizer : customizers) {
customizer.customize(config);
}
return config;
}
}
JSON Hypertext Application Language ( HAL ) のサポート
HAL 標準は、ウェブリンクを表現するためのシンプルなフォーマットです。
HAL のサポートを有効にするには、 quarkus-hal
エクステンションをプロジェクトに追加します。また、 HAL は JSON サポートを必要とするため、 quarkus-resteasy-jsonb
または quarkus-resteasy-jackson
のいずれかのエクステンションモジュールを追加する必要があります。
GAV | 使用方法 |
---|---|
|
エクステンションを追加したら、次は REST リソースにアノテーションを付け、メディアタイプ application/hal+json
(または RestMediaType.APPLICATION_HAL_JSON を使用) を生成できるようにします。例えば、以下のようになります。
@Path("/records")
public class RecordsResource {
@GET
@Produces({ MediaType.APPLICATION_JSON, "application/hal+json" })
@LinkResource(entityClassName = "org.acme.Record", rel = "list")
public List<TestRecord> getAll() {
// ...
}
@GET
@Path("/first")
@Produces({ MediaType.APPLICATION_JSON, "application/hal+json" })
@LinkResource(rel = "first")
public TestRecord getFirst() {
// ...
}
}
これで、エンドポイント /records
と /records/first
は、json
と hal+json
の両方のメディアタイプを受け入れ、レコードを Hal 形式で出力するようになります。
例えば、 curl を使用して /records
エンドポイントを呼び出してレコードのリストを返す場合、HAL 形式は次のようになります。
& curl -H "Accept:application/hal+json" -i localhost:8080/records
{
"_embedded": {
"items": [
{
"id": 1,
"slug": "first",
"value": "First value",
"_links": {
"list": {
"href": "http://localhost:8081/records"
},
"first": {
"href": "http://localhost:8081/records/first"
}
}
},
{
"id": 2,
"slug": "second",
"value": "Second value",
"_links": {
"list": {
"href": "http://localhost:8081/records"
},
"first": {
"href": "http://localhost:8081/records/first"
}
}
}
]
},
"_links": {
"list": {
"href": "http://localhost:8081/records"
}
}
}
When we call a resource /records/first
that returns only one instance, then the output is:
& curl -H "Accept:application/hal+json" -i localhost:8080/records/first
{
"id": 1,
"slug": "first",
"value": "First value",
"_links": {
"list": {
"href": "http://localhost:8081/records"
},
"first": {
"href": "http://localhost:8081/records/first"
}
}
}
フロントエンドの作成
それでは、FruitResource
とやり取りするための簡単なウェブページを追加してみましょう。
Quarkus は、META-INF/resources
ディレクトリーの下にある静的リソースを自動的に提供します。
src/main/resources/META-INF/resources
ディレクトリーに、この fruits.html ファイルのコンテンツを含む fruits.html
ファイルを追加します。
これで、REST サービスと対話できるようになりました。
-
以下のように Quarkus を起動します。
コマンドラインインタフェースquarkus dev
Maven./mvnw quarkus:dev
Gradle./gradlew --console=plain quarkusDev
-
ブラウザーで
http://localhost:8080/fruits.html
を開きます。 -
フォームを使って新しい果物をリストに追加します。
ネイティブ実行可能ファイルのビルド
以下のコマンドでネイティブの実行可能ファイルをビルドすることができます。
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
実行は簡単で、 ./target/rest-json-quickstart-1.0-SNAPSHOT-runner
を実行するだけです。
その後、ブラウザーで http://localhost:8080/fruits.html
を開いてアプリケーションを使用します。
シリアライゼーションについて
JSON シリアライズライブラリーは、 Java のリフレクションを使用してオブジェクトのプロパティーを取得してシリアライズします。
GraalVM でネイティブ実行可能ファイルを使用する場合、リフレクションで使用されるすべてのクラスを登録する必要があります。
幸いなことに、ほとんどの場合、Quarkus がその作業を自動的に実行します。
これまでのところ、Fruit
を含め、リフレクションを使用するためのクラスを 1 つも登録していませんが、すべて正常に動作しています。
Quarkusは、RESTメソッドからシリアライズされた型を推論することができる場合に、何らかのマジックを実行します。以下のようなRESTメソッドがある場合、Quarkusは、 Fruit
がシリアライズされると判断します。
@GET
public List<Fruit> list() {
// ...
}
Quarkus は、ビルド時に REST メソッドを分析することで、このような処理を自動的に実行します。そのため、このガイドの最初の部分ではリフレクション登録は必要ありませんでした。
Jakarta RESTの世界でよく見られるもう一つのパターンは、 Response
オブジェクトを使うことです。 Response
には、いくつかの良い特典があります:
-
メソッドで何が起こるかによって異なるエンティティータイプを返すことができます (たとえば
Legume
やError
)。 -
Response
の属性を設定できます (エラーが発生したときにステータスを知ることができます)。
REST メソッドは次のようになります。
@GET
public Response list() {
// ...
}
Quarkus は、情報が利用できないため、ビルド時に Response
に含まれるタイプを判別できません。
この場合、Quarkus は必要なクラスにリフレクションを自動的に登録できなくなります。
これが次のセクションにつながります。
レスポンスの使用
Fruit
クラスと同じモデルに従って、JSON としてシリアライズされる Legume
クラスを作成してみましょう。
package org.acme.rest.json;
public class Legume {
public String name;
public String description;
public Legume() {
}
public Legume(String name, String description) {
this.name = name;
this.description = description;
}
}
それでは、マメ科植物のリストを返すメソッドを 1 つだけ持つ LegumeResource
REST サービスを作成してみましょう。
このメソッドは Legume
のリストではなく Response
を返ます。
package org.acme.rest.json;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/legumes")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class LegumeResource {
private Set<Legume> legumes = Collections.synchronizedSet(new LinkedHashSet<>());
public LegumeResource() {
legumes.add(new Legume("Carrot", "Root vegetable, usually orange"));
legumes.add(new Legume("Zucchini", "Summer squash"));
}
@GET
public Response list() {
return Response.ok(legumes).build();
}
}
ここで、マメ科植物のリストを表示するための簡単なウェブページを追加してみましょう。
src/main/resources/META-INF/resources
ディレクトリーに、この legumes.html ファイルの内容を含む legumes.html
ファイルを追加します。
ブラウザーを開いて http://localhost:8080/legumes.html にアクセスすると、マメ科植物のリストが表示されます。
興味深いのは、アプリケーションをネイティブ実行可能ファイルとして実行するときです。
-
以下でネイティブの実行可能ファイルを作成します。
コマンドラインインタフェースquarkus build --native
Maven./mvnw install -Dnative
Gradle./gradlew build -Dquarkus.native.enabled=true
-
./target/rest-json-quickstart-1.0-SNAPSHOT-runner
で実行します。 -
ブラウザーを起動し、 http://localhost:8080/legumes.html にアクセスします。
そこにはマメ科植物はありません。
上記のように、問題は Quarkus が REST エンドポイントを分析することで Legume
クラスが何らかのリフレクションを必要とすることを判断できなかったことです。
JSON シリアライズライブラリーは、Legume
のフィールドのリストを取得しようとすると空のリストを取得するため、フィールドのデータをシリアライズしません。
現時点では、JSON-B や Jackson がクラスのフィールドのリストを取得しようとしたときに、そのクラスがリフレクションに登録されていない場合、例外は出力されません。 GraalVM は空のフィールドのリストを返します。 将来的にはこの点が変わり、エラーがより明白になることが期待されます。 |
Legume
クラスに @RegisterForReflection
アノテーションを追加することで、手動で Legume
を リフレクション用に登録することができます。
import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection
public class Legume {
// ...
}
@RegisterForReflection アノテーションは、ネイティブコンパイル時にクラスとそのメンバーを保持するよう Quarkus に指示します。 @RegisterForReflection アノテーションの詳細については、 ネイティブアプリケーションのヒントのページを参照してください。
|
それを実行して、今までと同じ手順を踏んでみましょう。
-
Ctrl+C
でアプリケーションを停止させます。 -
以下でネイティブの実行可能ファイルを作成します。
コマンドラインインタフェースquarkus build --native
Maven./mvnw install -Dnative
Gradle./gradlew build -Dquarkus.native.enabled=true
-
./target/rest-json-quickstart-1.0-SNAPSHOT-runner
で実行します。 -
ブラウザーを起動し、 http://localhost:8080/legumes.html にアクセスします。
今回はマメ科植物の一覧が表示されました。
リアクティブであること
リアクティブワークロードの場合は、常に Quarkus REST を使用してください。 |
非同期処理を処理するために リアクティブ型 を返すことができます。Quarkusでは、リアクティブで非同期なコードを書くために Mutiny の使用を推奨しています。
Mutiny と RESTEasy を統合するには、 quarkus-resteasy-mutiny
依存関係をプロジェクトに追加する必要があります。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-mutiny</artifactId>
</dependency>
implementation("io.quarkus:quarkus-resteasy-mutiny")
そして、エンドポイントは Uni
や Multi
のインスタンスを返すことができます。
@GET
@Path("/{name}")
public Uni<Fruit> getOne(@PathParam String name) {
return findByName(name);
}
@GET
public Multi<Fruit> getAll() {
return findAll();
}
単一の結果がある場合は Uni
を使用します。 Multi
は、非同期的に放出される可能性のある複数の項目がある場合に使用します。
Uni<Response>
のように、 Uni
と Response
を使用して、非同期 HTTP レスポンスを返すことができます。
Mutiny についての詳細は、 Mutiny - 直感的なリアクティブプログラミングライブラリー に記載されています。
HTTP フィルターとインターセプター
HTTP リクエストとレスポンスの両方とも、それぞれ ContainerRequestFilter
または ContainerResponseFilter
の実装を提供することで、インターセプトすることができます。
これらのフィルターは、メッセージに関連付けられたメタデータ (HTTP ヘッダー、クエリパラメーター、メディアタイプ、その他のメタデータ) を処理するのに適しています。
また、ユーザーがエンドポイントにアクセスする権限を持っていない場合などに、リクエスト処理を中止することもできます。
Let’s use ContainerRequestFilter
to add logging capability to our service. We can do that by implementing ContainerRequestFilter
and annotating it with the @Provider
annotation:
package org.acme.rest.json;
import io.vertx.core.http.HttpServerRequest;
import org.jboss.logging.Logger;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.Provider;
@Provider
public class LoggingFilter implements ContainerRequestFilter {
private static final Logger LOG = Logger.getLogger(LoggingFilter.class);
@Context
UriInfo info;
@Context
HttpServerRequest request;
@Override
public void filter(ContainerRequestContext context) {
final String method = context.getMethod();
final String path = info.getPath();
final String address = request.remoteAddress().toString();
LOG.infof("Request %s %s from IP %s", method, path, address);
}
}
これで、 REST メソッドが呼び出されるたびに、リクエストがログとしてコンソールに出力されるようになりました。
2019-06-05 12:44:26,526 INFO [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /legumes from IP 127.0.0.1
2019-06-05 12:49:19,623 INFO [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /fruits from IP 0:0:0:0:0:0:0:1
2019-06-05 12:50:44,019 INFO [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request POST /fruits from IP 0:0:0:0:0:0:0:1
2019-06-05 12:51:04,485 INFO [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /fruits from IP 127.0.0.1
CORS フィルター
クロスオリジンリソース共有 (CORS)は、ウェブページ上の制限されたリソースを、最初のリソースが提供されたドメイン以外の別のドメインから要求できるようにするメカニズムです。
Quarkus には、HTTP レイヤーレベルの CORS フィルターが含まれています。 CORS フィルターとその使用方法の詳細は、Quarkus のクロスオリジンリソース共有ガイドの CORS フィルター セクションを参照してください。
GZipのサポート
Quarkus では、デフォルトでは有効になっていませんが GZip をサポートしています。以下のプロパティーを使用して、GZipのサポートを設定することができます。
quarkus.resteasy.gzip.enabled=true (1)
quarkus.resteasy.gzip.max-input=10M (2)
1 | Gzipサポートを有効にします。 |
2 | 圧縮されたリクエストボディーの上限を設定します。
これは、攻撃の範囲を制限することで潜在的な攻撃を軽減するのに役立ちます。デフォルト値は 10M です。
この設定オプションは、[0-9]+[KkMmGgTtPpEeZzYy]? というフォーマット (正規表現として表示) の文字列を認識します。
接尾辞が指定されていない場合は、バイトであると想定されます。 |
GZip サポートが有効になったら、エンドポイントメソッドに @org.jboss.resteasy.annotations.GZIP
アノテーションを追加することで、エンドポイントで GZip サポートを使用できます。
また、HTTP レスポンスの圧縮をグローバルに有効にする設定プロパティー (quarkus.http.enable-compression ) もあります。
有効な場合、Content-Type HTTP ヘッダーが設定され、その値が quarkus.http.compress-media-types 設定プロパティーで設定された圧縮メディアタイプである場合、レスポンスボディーが圧縮されます。
|
マルチパートのサポート
RESTEasy は RESTEasy Multipart Provider を介してマルチパートをサポートしています。
Quarkusは 、 quarkus-resteasy-multipart
というエクステンションを提供しています。
このエクステンションは RESTEasy のデフォルトの動作とは若干異なり、リクエストで何も指定されていない場合のデフォルトの文字セットは US-ASCII ではなく UTF-8 となります。
この動作は、以下のプロパティーで設定できます。
ビルド時に固定される設定プロパティ - 他のすべての設定プロパティは実行時にオーバーライド可能
Configuration property |
型 |
デフォルト |
---|---|---|
Default charset. Note that the default value is UTF-8 which is different from RESTEasy’s default value US-ASCII. Environment variable: Show more |
|
|
The default content-type. Environment variable: Show more |
string |
|
サーブレットとの互換性
Quarkus では、 RESTEasy は Vert.x HTTP サーバーの上で直接実行するか、サーブレットに依存している場合は Undertow の上で実行することができます。
そのため、HttpServletRequest
などの特定のクラスは常に注入できるとは限りません。
このような特定のクラスのユースケースは、リモートクライアントの IP を取得する場合を除き、Jakarta REST の同等の機能でほとんどカバーされています。
RESTEasy には、注入できる代替 API HttpRequest
が付属しています。この API には、この問題を解決するためのメソッド getRemoteAddress()
および getRemoteHost()
があります。
RESTEasy と RESTクライアントのやりとり
Quarkus では、RESTEasy エクステンションと REST クライアントエクステンション が同じインフラストラクチャーを共有します。 この考慮事項の重要な影響の 1 つは、それらが (Jakarta REST の意味において) 同じプロバイダーのリストを共有することです。
たとえば、WriterInterceptor
を宣言すると、デフォルトではサーバーの呼び出しとクライアントの呼び出しの両方がインターセプトされますが、これは望ましい動作ではない可能性があります。
しかし、このデフォルトの動作を変更してプロバイダーに制約を設けることができます。
-
プロバイダーに
@ConstrainedTo(RuntimeType.SERVER)
アノテーションを追加することで、 サーバー の呼び出しのみを考慮します。 -
プロバイダーに
@ConstrainedTo(RuntimeType.CLIENT)
アノテーションを追加することで、 クライアント の呼び出しのみを考慮します。
Jakarta EE 開発との違い
単一のJakarta RESTアプリケーション限定
標準的なサーブレットコンテナで動作する Jakarta REST (および RESTEasy) とは対照的に、Quarkus は単一の Jakarta REST アプリケーションのデプロイメントのみをサポートしています。
複数の Jakarta REST Application
クラスが定義されている場合、ビルドは失敗し、Multiple classes have been annotated with @ApplicationPath which is currently not supported
というメッセージが表示されます。
複数の Jakarta REST アプリケーションが定義されている場合、プロパティ quarkus.resteasy.ignore-application-classes=true
を使用すると、すべての明示的な Application
クラスを無視することができます。これにより、すべてのリソース・クラスは、 quarkus.resteasy.path
(デフォルト: /
)で定義されるapplication-pathを介して利用可能になります。
Jakarta RESTアプリケーションのサポートの制限
RESTEasy エクステンションは、クラス jakarta.ws.rs.core.Application
のメソッド getProperties()
をサポートしていません。
さらに、メソッド getClasses()
および getSingletons()
のみに依存して、アノテーションが付けられたリソース、プロバイダー、および機能クラスをフィルタリングします。
組み込みのリソース、プロバイダー、機能クラスや、他のエクステンションで登録されたリソース、プロバイダ、機能クラスは除外されません。
最後に、メソッド getSingletons()
が返すオブジェクトは無視され、リソース、プロバイダー、機能クラスをフィルタリングするためにクラスのみが考慮されます。言い換えれば、メソッド getSingletons()
は実際には getClasses()
と同じように管理されます。
リソースのライフサイクル
Quarkus では、すべての Jakarta REST リソースは CDI Bean として扱われます。@Inject
を使って他の Bean を注入したり、@Transactional
などのバインディングを使ってインターセプターをバインドしたり、@PostConstruct
コールバックを定義したりすることが可能です。
リソースクラスにスコープアノテーションが宣言されていない場合、スコープはデフォルトに設定されます。
quarkus.resteasy.singleton-resources
プロパティーはデフォルトのスコープを制御できます。
true
(デフォルト) に設定すると、すべてのリクエストを処理するためにリソースクラスの 単一のインスタンス (@jakarta.inject.Singleton
で定義) が作成されます 。
false
に設定すると、リクエストごとにリソースクラスの 新しいインスタンス が作成されます。
明示的な CDI スコープアノテーション (@RequestScoped
、@ApplicationScoped
など) は、常にデフォルトの動作をオーバーライドし、リソースインスタンスのライフサイクルを指定します。
|
ビルド時条件でのJakarta RESTのクラスのインクルード/エクスクルード
Quarkusでは、CDI Beanと同様に、ビルド時の条件によって、Jakarta RESTリソース、プロバイダ、フィーチャーを直接取り込んだり除外したりすることができます。したがって、さまざまなJakarta RESTクラスにプロファイル条件( @io.quarkus.arc.profile.IfBuildProfile
または @io.quarkus.arc.profile.UnlessBuildProfile
)やプロパティ条件( io.quarkus.arc.properties.IfBuildProperty
または io.quarkus.arc.properties.UnlessBuildProperty
)をアノテーションして、ビルド時にQuarkusに対して、どのような条件の下でJakarta RESTクラスを含めるべきかを示すことができます。
次の例では、 Quarkus は、ビルドプロファイル app1
が有効になっている場合に限り、エンドポイント sayHello
を含めます。
@IfBuildProfile("app1")
public class ResourceForApp1Only {
@GET
@Path("sayHello")
public String sayHello() {
return "hello";
}
}
Jakarta REST Applicationが検出され、メソッド getClasses()
、 getSingletons()
がオーバーライドされている場合、Quarkusはビルド時の条件を無視し、Jakarta REST Applicationで定義されているもののみを考慮することに注意してください。