この記事では前回記事の続きとしてJSON データを扱うREST アプリケーションを作成する。このアプリケーションでは HTTP POST リクエストでJSON データを保存し、HTTP GET リクエストで保存済みJSONデータを取得することができる。
前回作成した example アプリケーションを元にソースコードの追加、編集を行う。
ソースコードの追加(Name.java)
Name クラスを Name.java で定義する。
Name クラスはフィールドとして id と name を持っている。それぞれについてゲッターとセッターのメソッドを定義している。
アプリケーションが保持するデータはこの Name クラスのインスタンスの集合として表される。
ソースコードの編集(NamesResources.java)
NamesResources クラスの定義を次のように変更する。
NamesResources.java
主な変更点:
・ApplicationScoped アノテーションをクラス定義に付加した
これにより、スコープを ApplicationScoped (アプリケーションスコープ)に設定して、このリソースクラスのインスタンスがアプリケーションで1つのみ生成されるようにしている。
これによって、names 変数を static にしなくても異なるリクエスト間でデータが保持されるようになる。
・names を Map から Set<Name> タイプに変更した
データの集合を HashSet<Name> として扱うため。
・Produces と Consumes のアノテーションをクラス定義にではなく、そのメソッドへ付加する形にした
これらのアノテーションはリソースクラスだけではなく、そのメソッドへも付加することができる。その場合はリソースクラスへの設定を上書きすることになる。(設定がない場合はすべてのメディアタイプのサポートを意味する)
・サポートするメディアタイプを TEXT_PLAIN から APPLICATION_JSON に変更した
これにより、get メソッドは Content-Type: application/json のレスポンスを生成し、post メソッドは Content-Type: application/json のリクエストのみを受け付けるようにしている。
ソースコードの編集(NotFoundExceptionMapper.java)
NotFoundExceptionMapper.java
toResponse メソッドをオーバーライドして、NotFoundException の例外が発生した場合のレスポンスを定義する。ここで使用している JsonObjectBuilder インターフェースとJson クラスは後述する JSON-P API に含まれる。
返り値として使用している Response クラスとそのメソッド等について詳細はAPI ドキュメントを参照のこと。
URL: jakarta.ee/specifications/platform/10/apidocs/jakarta/ws/rs/core/response
動作の確認
・指定した id のデータがない場合
URL で指定した id の値に対応するデータがない場合は、NotFoundException が発生する。NotFoundExceptionMapper クラスの toResponse メソッドで定義されるレスポンスが返される。
・POST でデータの追加
post メソッドではステータスコードを 201 に設定しており、レスポンスボディは定義していないのでレスポンスはヘッダーのみとなる。
(curl の -v オプションでHTTPヘッダーを含めて表示させている)
・指定した id のデータがある場合
Name クラスのインスタンスが JSON データに変換されてレスポンスとして返される。
Jakarta REST のエンティティプロバイダについて
Jakarta REST のアプリケーションではエンティティプロバイダ(Entity providers) が、リクエストまたはレスポンスのメッセージと Java タイプのマッピングサービスを提供する。
エンティティプロバイダには MessageBodyReader インターフェースと、 MessageBodyWriter インターフェースの2種類がある。
MessageBodyReader: リクエストメッセージから Java タイプへの変換
MessageBodyWriter: Java タイプからレスポンスメッセージへの変換
String タイプなど、仕様書で定められている複数のタイプについては、対応するMessageBodyReader と MessageBodyWriter が標準で実行環境中に含まれている。
実行環境がJSON-P(JSON Processing)、または JSON-B(JSON Binding) APIをサポートしている場合には、それぞれに対応した標準のエンティティプロバイダがJSON データと Java タイプとの間の変換に使われる。
Jakarta EE RESTful Web サービスでの JSON の処理
上で述べたように、Jakarta REST のアプリケーションで JSON データを扱う(クライアントからのリクエストとしてJSONの送信を受け付ける、レスポンスとしてJSONを返す等)ための API には JSON-P(JSON Processing) と JSON-B(JSON Binding) の2種類が存在する。
このアプリケーションで使用している Open Liberty 6.0 のMicroProfile 6.0 では jsonp-2.1 と jsonb-3.0 が機能として有効になっている。
URL: openliberty.io/docs/latest/reference/feature/microProfile-6.0.html
NamesResource クラスの get メソッドでは返り値タイプが Name クラスになっているので、Name クラスオブジェクトからJSON データへの変換が必要となっている。
この変換には対応するエンティティプロバイダ(MessageBodyWriter)が使われる。
また、post メソッドではパラメータが Name クラスになっているので、JSON データから Name クラスオブジェクトへの変換を行うのに、対応するエンティティプロバイダ
(MessageBodyReader)が使われることになる。
一般的な Java クラスからJSON データ(メディアタイプは application/json など)への変換には JSON-B API が使用される。 詳細は Jakarta JSON Binding の仕様書を参照のこと。
get メソッドで NotFoundException の例外が発生した場合に返されるレスポンスは
Name オブジェクトではなく、NotFoundExceptionMapper クラスの toResponse メソッドで返される Response オブジェクトが使われる。
この場合には Response オブジェクトのエンティティとして設定されている JsonObject のインスタンスが、対応するエンティティプロバイダによって JSON データに変換されることになる。
JsonObject インターフェースからの JSON データへの変換には JSON-P に対応するものと JSON-Bに対応するエンティティプロバイダが存在する。JSON-B と JSON-Pの両方をサポートする実行環境では JSON-B に対応するエンティティプロバイダが優先すると Jakarta REST の仕様書には記載されている。
参考資料
資料としては主に "Jakarta RESTful Web Services 3.0" の仕様書を参考にしている。Jakarta EE Tutorial のサイトの20章にもJSON の処理について記載がある。
URL: eclipse-ee4j.github.io/jakartaee-tutorial/#json-processing
JSON-P(JSON Processing) の API ドキュメントは下記ページで参照できる。
URL: jakarta.ee/specifications/jsonp/2.1/apidocs/
JSON-B(JSON Binding) の仕様は下記ページで参照できる。
URL: jakarta.ee/specifications/jsonb/
コメント: 記事内の情報は著者が個人的に調べた範囲で理解しているものです。必要に応じて訂正する場合があります。記事中に含まれるURL はプロトコルを含めると禁止ワードに引っ掛かるので省いています。
著者・投稿者: ENARTS05
編集履歴:
2024/3/5 作成