RESTEasy Classic
|
このガイドは、Quarkus 2.8 までデフォルトの Jakarta REST (旧称 JAX-RS) 実装であった RESTEasy Classic に関するものです。 It is now recommended to use RESTEasy Reactive, which supports both traditional blocking workloads and reactive workloads equally well. For more information about RESTEasy Reactive, please see the introductory REST JSON guide or the RESTEasy Reactive reference documentation. |
| 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 ハイパーテキストアプリケーション言語 (HAL) のサポート
HAL 標準は、Web リンクを表す単純な形式です。
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 devMaven./mvnw quarkus:devGradle./gradlew --console=plain quarkusDev -
ブラウザで
http://localhost:8080/fruits.htmlを開きます。 -
フォームを使って新しいフルーツをリストに追加します
ネイティブ実行可能ファイルのビルド
通常のコマンドでネイティブ実行可能ファイルをビルドすることができます:
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.package.type=native
実行は簡単で、 ./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 サービスを作成してみましょう。
このメソッドは Response を返し、 Legume のリストではありません。
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 --nativeMaven./mvnw install -DnativeGradle./gradlew build -Dquarkus.package.type=native -
./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 --nativeMaven./mvnw install -DnativeGradle./gradlew build -Dquarkus.package.type=native -
./target/rest-json-quickstart-1.0-SNAPSHOT-runnerで実行します -
ブラウザで http://localhost:8080/legumes.html を開きます
今回はマメ科の一覧が表示されました。
Reactiveになる
|
リアクティブなワークロードには、常に RESTEasy Reactive を使用してください。 |
非同期処理を処理するために リアクティブ型 を返すことができます。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 を使用して、非同期 HTTP レスポンスを返すことができます: Uni<Response> .
Mutinyについての詳細は、 Mutiny - 直感的なリアクティブプログラミングライブラリ に記載されています。
HTTP フィルターとインターセプター
HTTP リクエストとレスポンスの両方とも、それぞれ ContainerRequestFilter または ContainerResponseFilter の実装を提供することで、インターセプトすることができます。
これらのフィルターは、メッセージに関連付けられたメタデータ (HTTP ヘッダー、クエリパラメーター、メディアタイプ、その他のメタデータ) を処理するのに適しています。
また、ユーザーがエンドポイントにアクセスする権限を持っていない場合などに、リクエスト処理を中止することもできます。
ContainerRequestFilter を使用して、サービスにロギング機能を追加してみましょう。 ContainerRequestFilter を実装して、 @Provider アノテーションをつけることで実現できます。
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 となります。
この動作は、以下のプロパティーで設定できます。
ビルド時に固定される設定プロパティ - 他のすべての設定プロパティは実行時にオーバーライド可能
タイプ |
デフォルト |
|
|---|---|---|
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アプリケーション限定
In contrast to Jakarta REST (and RESTeasy) running in a standard servlet container, Quarkus only supports the deployment of a single Jakarta REST application.
If multiple Jakarta REST Application classes are defined, the build will fail with the message 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で定義されているもののみを考慮することに注意してください。