RESTEasy Classic
このガイドは、Quarkus 2.8までデフォルトのJakarta REST(旧称JAX-RS)実装であった RESTEasy Classic について扱います。 従来のブロック型ワークロードとリアクティブ型ワークロードの両方を同等にサポートするRESTEasy Reactiveを使用することが推奨されるようになりました。RESTEasy Reactiveの詳細については、 REST JSON入門ガイド または RESTEasy Reactiveのリファレンスドキュメント をご覧ください。 |
RESTEasy Classic をベースにした REST クライアント( JSON のサポートを含む)が必要な場合は、別のガイドを参照してください。 |
アーキテクチャ
このガイドで開発するアプリケーションは非常にシンプルです。 ユーザーはフォームを使用してリストに要素を追加することができ、リストが更新されます。
ブラウザとサーバー間の情報はすべて JSON 形式になっています。
Maven プロジェクトの作成
最初に、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。
Windowsユーザーの場合:
-
If using cmd, (don’t use backward slash
\
and put everything on the same line) -
If using Powershell, wrap
-D
parameters in double quotes e.g."-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ユーザーの場合:
-
If using cmd, (don’t use backward slash
\
and put everything on the same line) -
If using Powershell, wrap
-D
parameters in double quotes e.g."-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
機能を無効にすることで不明なプロパティを無視するように設定されています。
application.properties
で quarkus.jackson.fail-on-unknown-properties=true
を設定するか、 クラスごとに @JsonIgnoreProperties(ignoreUnknown = false)
を設定することで、Jackson のデフォルトの動作を復元することができます。
さらに、ObjectMapper
は、 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
機能を無効化することで日付と時刻を ISO-8601 でフォーマットするように設定されています。
application.properties
で quarkus.jackson.write-dates-as-timestamps=true
を設定すると、Jackson のデフォルトの動作を復元することができます。単一のフィールドのフォーマットを変更したい場合は、@JsonFormat
アノテーションを使用することができます。
また、 Quarkus では、 CDI Bean を介して様々な Jackson の設定を非常に簡単に設定することができます。最も単純な、そして推奨されるアプローチは、 io.quarkus.jackson.ObjectMapperCustomizer
型の CDI Bean を定義し、その中であらゆる 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"
}
}
}
フロントエンドの作成
Now let’s add a simple web page to interact with our FruitResource
. Quarkus automatically serves static resources located under the META-INF/resources
directory. In the src/main/resources/META-INF/resources
directory, add a fruits.html
file with the content from this fruits.html file in it.
これで、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.package.type=native
実行は簡単で、 ./target/rest-json-quickstart-1.0-SNAPSHOT-runner
を実行するだけです。
その後、ブラウザーで http://localhost:8080/fruits.html
を開いてアプリケーションを使用します。
シリアライゼーションについて
JSON シリアライズライブラリーは、 Java のリフレクションを使用してオブジェクトのプロパティーを取得してシリアライズします。
GraalVM でネイティブ実行可能ファイルを使用する場合、リフレクションで使用されるすべてのクラスを登録する必要があります。幸いなことに、 Quarkus はその作業のほとんどを代行してくれます。 これまでのところ、 Fruit
でさえ、リフレクションを使用するためのクラスを登録しておらず、すべてが正常に動作しています。
Quarkus は、 REST メソッドからシリアライズされた型を推論することができる場合に、何らかの妙技を実行します。以下のような REST メソッドがある場合、 Quarkus は、 Fruit
がシリアライズされることを決定します。
@GET
public List<Fruit> list() {
// ...
}
Quarkusは 、ビルド時に REST メソッドを分析することで自動的にこれを行います。そのため、このガイドの最初の部分では、リフレクションを登録する必要がありませんでした。
Jakarta RESTの世界でよく見られるもう一つのパターンは、 Response
オブジェクトを使うことです。 Response
には、いくつかの良い特典があります:
-
メソッド内で発生した内容に応じて異なるエンティティータイプを返すことができます ( 例えば
Legume
やError
) 。 -
Response
の属性 ( エラーの場合は、そのステータスなど ) を設定することができます。
REST メソッドは次のようになります。
@GET
public Response list() {
// ...
}
Response
に含まれるタイプは情報がないため、Quarkusがビルド時に判断することはできません。この場合、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;
}
}
それでは、マメ科植物 ( Legume ) のリストを返すメソッドを一つだけ持つ 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.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 --native
Maven./mvnw install -Dnative
Gradle./gradlew build -Dquarkus.package.type=native
-
./target/rest-json-quickstart-1.0-SNAPSHOT-runner
で実行します。 -
ブラウザーを起動し、 http://localhost:8080/legumes.html にアクセスします。
今回はマメ科植物の一覧が表示されました。
リアクティブであること
リアクティブなワークロードには、常に 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>
のように、 Uni
と Response
を使用して、非同期 HTTP レスポンスを返すことができます。
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 には、 CORS フィルターが付属しています。使用方法については、 HTTP リファレンスドキュメント を参照してください。
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
アノテーションを追加することで、エンドポイントで使用することができます。
また、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 これは、getRemoteAddress() メソッドと getRemoteHost() メソッドを持っており、この問題を解決することができます。
RESTEasy と RESTクライアントのやりとり
Quarkusでは、RESTEasyエクステンションと REST Clientエクステンション は、同じインフラストラクチャを共有しています。この考慮の重要な結果の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で定義されているもののみを考慮することに注意してください。