4.3. Java オブジェクトとの間のマーシャリング
HTTP で送信するための Java オブジェクトのマーシャリング
REST プロトコルを使用する最も一般的な方法の 1 つは、Java Bean の内容をメッセージボディーで送信することです。これを実現させるには、Java オブジェクトを適切なデータフォーマットとの間でマーシャリングするメカニズムが必要です。Java オブジェクトのエンコードに適した以下のデータフォーマットが REST DSL でサポートされています。
- JSON
JSON (JavaScript Object Notation) は、Java オブジェクトとの間で簡単にマッピングできる軽量なデータフォーマットです。JSON 構文はコンパクトで、緩く型指定され、人間が読み書きがしやすい構文です。これらの理由から、JSON は REST サービスのメッセージ形式として人気があります。
たとえば、以下の JSON コードは、
id
とname
の 2 つのプロパティーフィールドを持つUser
Bean を表現できます。{ "id" : 1234, "name" : "Jane Doe" }
- JAXB
JAXB(Java Architecture for XML Binding) は、Java オブジェクトと XML の間で簡単にマッピングできるデータフォーマットです。XML を Java オブジェクトにマーシャリングするには、使用する Java クラスにアノテーションを付ける必要があります。
たとえば、以下の JAXB コードは、
id
とname
の 2 つのプロパティーフィールドを持つUser
Bean を表現できます。<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <User> <Id>1234</Id> <Name>Jane Doe</Name> </User>
注記Camel 2.17.0 以降、JAXB データフォーマットと型コンバーターは、
XmlRootElement
の代わりにObjectFactory
を使用するクラスの XML から POJO への変換をサポートします。また、Camel コンテキストでは、値が true のCamelJaxbObjectFactory
プロパティーを含める必要があります。ただし、後方互換のためにデフォルトは false になっています。
REST DSL による JSON と JAXB の統合
メッセージボディーを Java オブジェクトへ変換するために必要なコードを自分で書くこともできます。しかし、REST DSL は、この変換を自動的に実行する利便性を提供します。特に、JSON と JAXB を REST DSL と統合すると、以下のようなメリットがあります。
- Java オブジェクトとの間のマーシャリングは自動的に実行されます (適切な設定がある場合)。
- REST DSL は、データフォーマット (JSON または JAXB のいずれか) を自動的に検出し、適切な変換を行うことができます。
- REST DSL は 抽象化レイヤー を提供するので、開発するコードは JSON または JAXB 実装に固有のものではありません。そのため、アプリケーションコードへの影響を最小限に抑えながら、後から実装を切り替えることができます。
サポートされるデータフォーマットコンポーネント
Apache Camel は JSON と JAXB データフォーマットの多くの実装を提供しています。現在、REST DSL では以下のデータフォーマットがサポートされています。
JSON
-
Jackson データフォーマット (
camel-jackson
) (デフォルト) -
gson データフォーマット (
camel-gson
) -
XStream データフォーマット (
camel-xstream
)
-
Jackson データフォーマット (
JAXB
-
JAXB データフォーマット (
camel-jaxb
)
-
JAXB データフォーマット (
オブジェクトマーシャリングを有効にする方法
REST DSL でオブジェクトのマーシャリングを有効にする場合は、以下の点に注意してください。
-
bindingMode
オプションを設定してバインディングモードを有効にします (バインディングモードを設定できるレベルはいくつかあり、詳細は 「バインディングモードの設定」 を参照してください)。 -
受信メッセージでは
type
オプション (必須)、送信メッセージではoutType
オプション (任意) を使用して、変換先 (または変換元) の Java 型を指定します。 - Java オブジェクトを JAXB データフォーマットとの間で変換する場合、Java クラスに適切な JAXB アノテーションを付ける必要があります。
-
jsonDataFormat
オプションやxmlDataFormat
オプション (restConfiguration
ビルダーで指定可能) を使用して、ベースとなるデータフォーマットの実装を指定します。 ルートが JAXB 形式の戻り値を提供する場合、通常、エクスチェンジボディーの Out メッセージを JAXB アノテーションを持つクラスのインスタンス (JAXB 要素) に設定することが期待されます。ただし、JAXB の戻り値を XML 形式で直接提供する場合は、キー
xml.out.mustBeJAXBElement
でdataFormatProperty
をfalse
に設定します (restConfiguration
ビルダーで指定可能)。たとえば、XML DSL の構文では以下になります。<restConfiguration ...> <dataFormatProperty key="xml.out.mustBeJAXBElement" value="false"/> ... </restConfiguration>
必要な依存関係をプロジェクトのビルドファイルに追加します。たとえば、Maven ビルドシステムを使用し、Jackson データフォーマットを使用している場合、次の依存関係を Maven POM ファイルに追加します。
<?xml version="1.0" encoding="UTF-8"?> <project ...> ... <dependencies> ... <!-- use for json binding --> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jackson</artifactId> </dependency> ... </dependencies> </project>
アプリケーションを OSGi コンテナーにデプロイする際には、必ず選択したデータフォーマットに必要な機能をインストールしてください。たとえば、Jackson データフォーマット (デフォルト) を使用している場合、以下の Karaf コンソールコマンドを入力して
camel-jackson
機能をインストールします。JBossFuse:karaf@root> features:install camel-jackson
また、Fabric 環境にデプロイする場合は、Fabric プロファイルにその機能を追加します。たとえば、プロファイル
MyRestProfile
を使用している場合は、次のコンソールコマンドを入力して機能を追加できます。JBossFuse:karaf@root> fabric:profile-edit --features camel-jackson MyRestProfile
バインディングモードの設定
bindingMode
オプションはデフォルトで off
になっているため、Java オブジェクトのマーシャリングを有効にするには、明示的に設定する必要があります。表は、サポートされているバインディングモードの一覧を示しています。
Camel 2.16.3 以降では、POJO から JSon/JAXB へのバインディングは、content-type ヘッダーに json または xml が含まれている場合にのみ発生します。これにより、カスタムのコンテンツタイプを指定することで、メッセージボディーがバインディングを使用してマーシャリングしなくなります。これは、メッセージボディーがカスタムバイナリーのペイロードである場合などに便利です。
バインディングモード | 説明 |
---|---|
| バインディングはオフになります (デフォルト)。 |
| バインディングは JSON または XML に対して有効になります。このモードでは、Camel は受信メッセージのフォーマットに基づいて JSON または XML (JAXB) を自動選択します。必ずしも両方のデータフォーマットの実装を有効にする必要はありません。JSON の実装と XML の実装のどちらかまたは両方をクラスパスで提供します。 |
|
バインディングは JSON でのみ有効になります。クラスパスに JSON の実装を用意 しなければなりません (デフォルトでは、Camel は |
|
バインディングは XML でのみ有効です。クラスパスに XML の実装を用意 しなければなりません (デフォルトでは、Camel は |
| バインディングは JSON と XML の両方に対して有効になります。このモードでは、Camel は受信メッセージのフォーマットに基づいて JSON または XML (JAXB) を自動選択します。クラスパスに 両方 のデータフォーマットの実装を用意する必要があります。 |
Java では、これらのバインディングモード値は、以下の enum
型のインスタンスとして表されます。
org.apache.camel.model.rest.RestBindingMode
bindingMode
が設定できるレベルは、以下のように複数あります。
- REST DSL の設定
以下のように、
restConfiguration
ビルダーからbindingMode
オプションを設定できます。restConfiguration().component("servlet").port(8181).bindingMode(RestBindingMode.json);
- サービス定義のベースパート
rest()
キーワードの直後 (Verb 句の前) に、以下のようにbindingMode
オプションを設定することができます。rest("/user").bindingMode(RestBindingMode.json).get("/{id}").VerbClause
- Verb 句
Verb 句で
bindingMode
オプションを設定する場合は、以下のようになります。rest("/user") .get("/{id}").bindingMode(RestBindingMode.json).to("...");
例
Servlet コンポーネントを REST 実装として使用して、REST DSL を使用する方法を示す完全なコード例は、Apache Camel の camel-example-servlet-rest-blueprint
の例を参照してください。この例は、スタンドアロンの Apache Camel ディストリビューション apache-camel-2.23.2.fuse-780036-redhat-00001.zip
をインストールして見ることができます。これは、Fuse インストールの extras/
サブディレクトリーにあります。
スタンドアロン Apache Camel ディストリビューションのインストール後に、以下のディレクトリーでサンプルコードを確認できます。
ApacheCamelInstallDir/examples/camel-example-servlet-rest-blueprint
REST 実装として Servlet コンポーネントを設定
camel-example-servlet-rest-blueprint
の例では、REST DSL のベースとなる実装は Servlet コンポーネントによって提供されます。Servlet コンポーネントは、例4.1「REST DSL の Servlet コンポーネントの設定」 に示されているように、Blueprint XML ファイルで設定されます。
例4.1 REST DSL の Servlet コンポーネントの設定
<?xml version="1.0" encoding="UTF-8"?> <blueprint ...> <!-- to setup camel servlet with OSGi HttpService --> <reference id="httpService" interface="org.osgi.service.http.HttpService"/> <bean class="org.apache.camel.component.servlet.osgi.OsgiServletRegisterer" init-method="register" destroy-method="unregister"> <property name="alias" value="/camel-example-servlet-rest-blueprint/rest"/> <property name="httpService" ref="httpService"/> <property name="servlet" ref="camelServlet"/> </bean> <bean id="camelServlet" class="org.apache.camel.component.servlet.CamelHttpTransportServlet"/> ... <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <restConfiguration component="servlet" bindingMode="json" contextPath="/camel-example-servlet-rest-blueprint/rest" port="8181"> <dataFormatProperty key="prettyPrint" value="true"/> </restConfiguration> ... </camelContext> </blueprint>
Servlet コンポーネントを REST DSL で設定するには、以下の 3 つのレイヤーを設定する必要があります。
- REST DSL レイヤー
-
REST DSL レイヤーは
restConfiguration
要素によって設定され、component
属性をservlet
という値に設定することで Servlet コンポーネントと統合されます。 - Servlet コンポーネントレイヤー
-
Servlet コンポーネントレイヤーは、クラス
CamelHttpTransportServlet
のインスタンスとして実装され、このサンプルインスタンスには Bean IDcamelServlet
があります。 - HTTP コンテナーレイヤー
Servlet コンポーネントは HTTP コンテナーにデプロイする必要があります。Karaf コンテナーには通常、ポート 8181 の HTTP リクエストをリッスンするデフォルトの HTTP コンテナー (Jetty HTTP コンテナー) が提供されています。Servlet コンポーネントをデフォルトの Jetty HTTP コンテナーにデプロイするには、以下を行います。
-
OSGi サービス (
org.osgi.service.http.HttpService
) への OSGi 参照を取得します。このサービスは、OSGi のデフォルト HTTP サーバーへのアクセスを提供する標準化された OSGi インターフェイスです。 -
ユーティリティークラスのインスタンス (
OsgiServletRegisterer
) を作成して、HTTP コンテナーに Servlet コンポーネントを登録します。OsgiServletRegisterer
クラスは、Servlet コンポーネントのライフサイクル管理を簡素化するユーティリティーです。このクラスのインスタンスが作成されると、HttpService
OSGi サービス上のregisterServlet
メソッドが自動的に呼び出され、インスタンスが破棄されると、unregister
メソッドが自動的に呼び出されます。
-
OSGi サービス (
必要な依存関係
この例には、REST DSL にとって重要な以下の 2 つの依存関係があります。
- Servlet コンポーネント
REST DSL のベースとなる実装を提供します。以下のように Maven POM ファイルで指定します。
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-servlet</artifactId> <version>${camel-version}</version> </dependency>
また、OSGi コンテナーにデプロイする場合、以下のように Servlet コンポーネント機能をインストールする必要があります。
JBossFuse:karaf@root> features:install camel-servlet
- Jackson データフォーマット
JSON データフォーマットの実装を提供します。以下のように Maven POM ファイルで指定します。
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jackson</artifactId> <version>${camel-version}</version> </dependency>
また、OSGi コンテナーにデプロイする場合、以下のように Jackson データフォーマット機能をインストールする必要があります。
JBossFuse:karaf@root> features:install camel-jackson
レスポンス用 の Java 型
サンプルアプリケーションは、HTTP リクエストメッセージとレスポンスメッセージで User
型のオブジェクトを渡し合います。Java クラス User
は、例4.2「JSON レスポンス用ユーザークラス」 で示すように定義されます。
例4.2 JSON レスポンス用ユーザークラス
// Java package org.apache.camel.example.rest; public class User { private int id; private String name; public User() { } public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
クラス User
は、JSON データ形式で比較的シンプルに表現されます。たとえば、JSON 形式で表現されたこのクラスのインスタンスは次のようになります。
{ "id" : 1234, "name" : "Jane Doe" }
JSON バインディングを使用した REST DSL の例
この例の REST DSL 設定と REST サービス定義を 例4.3「JSON バインディングでの REST DSL の例」 に示します。
例4.3 JSON バインディングでの REST DSL の例
<?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...> ... <!-- a bean for user services --> <bean id="userService" class="org.apache.camel.example.rest.UserService"/> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <restConfiguration component="servlet" bindingMode="json" contextPath="/camel-example-servlet-rest-blueprint/rest" port="8181"> <dataFormatProperty key="prettyPrint" value="true"/> </restConfiguration> <!-- defines the REST services using the base path, /user --> <rest path="/user" consumes="application/json" produces="application/json"> <description>User rest service</description> <!-- this is a rest GET to view a user with the given id --> <get uri="/{id}" outType="org.apache.camel.example.rest.User"> <description>Find user by id</description> <to uri="bean:userService?method=getUser(${header.id})"/> </get> <!-- this is a rest PUT to create/update a user --> <put type="org.apache.camel.example.rest.User"> <description>Updates or create a user</description> <to uri="bean:userService?method=updateUser"/> </put> <!-- this is a rest GET to find all users --> <get uri="/findAll" outType="org.apache.camel.example.rest.User[]"> <description>Find all users</description> <to uri="bean:userService?method=listUsers"/> </get> </rest> </camelContext> </blueprint>
REST オペレーション
例4.3「JSON バインディングでの REST DSL の例」 からの REST サービスは、以下の REST オペレーションを定義します。
GET /camel-example-servlet-rest-blueprint/rest/user/{id}
-
{id}
で識別されたユーザーの詳細を取得します。HTTP レスポンスは JSON 形式で返されます。 PUT /camel-example-servlet-rest-blueprint/rest/user
-
新しいユーザーを作成します。ユーザーの詳細は PUT メッセージのボディーに含まれ、JSON 形式でエンコードされます (
User
オブジェクトタイプと一致するように)。 GET /camel-example-servlet-rest-blueprint/rest/user/findAll
- すべてのユーザーの詳細を取得します。HTTP レスポンスはユーザーの配列で、JSON 形式で返されます。
REST サービスを呼び出すための URL
例4.3「JSON バインディングでの REST DSL の例」 から REST DSL の定義を調べることで、各 REST オペレーションを呼び出すのに必要な URL をまとめることができます。たとえば、指定した ID を持つユーザーの詳細を返す最初の REST オペレーションを呼び出す場合、URL は以下になります。
http://localhost:8181
-
restConfiguration
では、プロトコルのデフォルトはhttp
で、ポートは明示的に8181
に設定されます。 /camel-example-servlet-rest-blueprint/rest
-
restConfiguration
要素のcontextPath
属性によって指定されます。 /user
-
rest
要素のpath
属性によって指定されます。 /{id}
-
verb 要素
get
のuri
属性によって指定されます。
したがって、コマンドラインで以下のコマンドを入力することで、curl
ユーティリティーでこの REST 操作を呼び出すことができます。
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/123
同様に、残りの REST オペレーションは、以下のサンプルコマンドを入力することにより、curl
で呼び出すことができます。
curl -X GET -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user/findAll curl -X PUT -d "{ \"id\": 666, \"name\": \"The devil\"}" -H "Accept: application/json" http://localhost:8181/camel-example-servlet-rest-blueprint/rest/user