Spring での Object/XML マッピングのサポートを探る

Spring フレームワークを使ったマーシャリングとアンマーシャリング

Java™ EE (Java Platform, Enterprise Edition) コミュニティーの中で、Spring は広く受け入れられたフレームワークになりつつあります。Spring の最新リリースの新機能の 1 つとして、O/X (Object/XML) マッピングがサポートされています。この API を利用することで、Java オブジェクトを XML に、あるいは XML を Java オブジェクトに変換することができます。この記事では、Spring の Object/XML マッピングの使い方と、そのメリットについて学びます。

Brian M. Carey, Senior Systems Engineer, Triangle Information Solutions

Photo of Brian CareyBrian Carey は情報システムのコンサルタントであり、Java、Java Enterprise、PHP、Ajax、そしてそれらの関連技術を専門としています。Twitter で Brian Carey をフォローするためには http://twitter.com/brianmcarey にアクセスしてください。



2009年 10月 20日

Spring とは何か

よく使われる頭字語

  • API: Application Programming Interface
  • IDE: Integrated Development Environment
  • XML: Extensible Markup Language

Spring は Rod Johnson によって開発された堅牢な Java アプリケーション・フレームワークであり、Java 開発コミュニティーの中で広く受け入れられています。Spring は、「依存性注入」、「制御の反転」、「アスペクト指向プログラミング」といった高度な技術を表す専門用語でも有名です。また Spring は MVC (Model-View-Controller) パターンをサポートしており、多種多様なデータベース・ドライバーと適切にやり取りしてデータベースのデータにアクセスすることもできます。また Spring は、トランザクション管理、単体テスト、バッチ・プロセス、セキュリティーもサポートしています。

Spring は評判も高く、長い間使われていることから、迅速なアプリケーション開発に不可欠のフレームワークと見なされることがよくあります。そして、おそらく何よりも良いことに、Spring は無料です。

O/X マッパーとは何か

Spring 3.0 での新機能が O/X マッパーです。O/X マッパーの概念は新しいものではありません。O はオブジェクトを表し、X は XML を表します。O/X マッパーというのは、Java オブジェクト (ほとんどの場合は POJO (Plain Old Java Object)) を XML 文書に変換したり、その逆変換をしたりするためのものです。

例えば、いくつかの属性を持つ単純な Bean があり、その Java オブジェクトを XML 文書に変換することがビジネス上必要だとします。それを Spring の O/X マッパーが処理してくれるのです。また、その逆が必要な場合 (つまり、XML 文書を単純な Java Bean に変換する必要がある場合) にも、それを Spring の O/X マッパーが処理してくれます。

ここで、Spring の O/X マッパーは単に一貫性のあるインターフェースを定義するだけであり、そうしたインターフェースの実装は一般的なサードパーティーのフレームワークで行われることに注意してください。Spring の O/X 機能を利用するためには、Java オブジェクトから XML への変換とその逆変換を行うユーティリティーが必要です。そのためによく使われるサードパーティーのツールの 1 つが、この記事で使用する Castor です。他のツールには、XMLBeans、JAXB (Java Architecture for XML Binding)、JiBX、XStream などがあります。

マーシャリングとアンマーシャリング

O/X マッピングと関連して、マーシャリングとアンマーシャリングという用語を目にすることがよくあります。

マーシャリングというのは、Java Bean を XML 文書に変換するプロセスのことを言います。これは、Bean のすべてのフィールド、そしてフィールドのすべての値が、作成される XML ファイルの中に XML の要素または属性として追加されるということです。マーシャリングはシリアライズと呼ばれることもあります。

アンマーシャリングは、ご想像のとおり、マーシャリングとはまったく逆のプロセスであり、XML 文書を Java Bean に変換するプロセスのことを言います。これは、XML 文書のすべての要素または属性が Java Bean に Java のフィールドとして追加され、それらの要素または属性の値は追加される Java フィールドの値になるということです。アンマーシャリングはデシリアライズと呼ばれることもあります。

Spring の O/X マッパーを使うメリット

Spring の O/X マッパーを使うことによる直接のメリットの 1 つは、Spring フレームワークの他の側面を利用して構成を単純化できることです。Spring の Bean ファクトリーを利用すると、インスタンス化された O/X マーシャラーをオブジェクトの中に直接注入して使用することができます (これが先ほど触れた「依存性注入」です)。先ほどのポイントの繰り返しになりますが、これによってアプリケーションの開発とデプロイメントを容易に行えるようになります。

Spring の O/X フレームワークでは、オブジェクト指向設計の堅実なプラクティスに従って単純に 2 つのインターフェース (MarshallerUnmarshaller) を定義しており、これらのインターフェースを使って O/X 機能が実行されます。これも、フレームワークを使うことによる大きなメリットの 1 つです。これらのインターフェースの実装は完全に個々の開発者次第であり、コーディングを変更せずに容易に実装を切り換えることができます。例えば、O/X のために Castor を使っているものの、必要な機能が Castor に欠けていると思った場合には、コーディングを変更せずに XMLBeans に切り換えることができます。単純に新しい O/X フレームワークを使用するように Spring の構成ファイルを変更すればよいのです。

Spring の O/X マッパーを使用することによる、もう 1 つのメリットは、例外の階層構造が一貫性を持っていることです。Spring フレームワークは Spring のデータ・アクセス・モジュールによって確立されるパターンに従い、O/X マッパーの適用対象となるコードの例外オブジェクトを (O/X マッパー専用に確立される) Spring 独自のランタイム例外の中にラップします。このため、サードパーティーのプロバイダーによってスローされる例外は Spring のランタイム例外の中にラップされ、その例外の根本原因を見失うことはありません。また、例外はランタイム例外の中にラップされるため、特定の例外をキャッチするためにコードを変更する必要はありません。基底例外 XMLMappingException は、他のいくつかのランタイム例外に継承されます (GenericMarshallingFailureExceptionValidationFailureExceptionMarshallingFailureExceptionUnmarshallingFailureException など)。

簡単なデモ

ここまでで Spring のO/X マッパーの背景と基本について説明したので、このO/X マッパーの使い方を調べてみましょう。この記事ではまず、Java Enterprise にまったく依存しない単純な Spring アプリケーションを作成します。そのために、単純な Java クラスを作成し、その Java クラスが Spring の構成ファイルにアクセスしてそのクラスをインスタンス化し、O/X 依存性を注入するようにします。次に、このクラスのインスタンスを使って単純な Java Bean のマーシャリングとアンマーシャリングを行います。構成ファイルを含め、すべてのソース・ファイルへのリンクは「ダウンロード」を参照してください。

コーディング

最初に注目しなければならないのは、Spring の構成ファイルです。リスト 1 は、このアプリケーションがマーシャリングとアンマーシャリングを実行するために使用する構成ファイルです。このファイルは、マーシャリングとアンマーシャリングの実行時には、クラスパスに存在していなければならないことに注意してください。

リスト 1. 構成ファイル
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="oxmExample" class="com.xyz.OXMExample">
        <property name="marshaller" ref="castorMarshaller" />
        <property name="unmarshaller" ref="castorMarshaller" />
    </bean>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
    	<property name="mappingLocation" value="classpath:mapping.xml" />
    </bean>
</beans>

ご覧のように、構成ファイルには 2 つの Bean が定義されているだけです。そのため、すべては単純です。最初の Bean は、このデモの実行に使われるクラス (com.xyz.OXMExample) です。このクラスに関連する 2 つのプロパティーは依存性注入を使います。どちらのプロパティーの場合も、依存性注入は castorMarshaller Bean のインスタンスによって行われます。これは Spring フレームワークで Bean を定義するための標準的な方法です (経験豊富な Spring 開発者ならばすぐにおわかりのことと思います)。

もう 1 つの Bean は castorMarshaller Bean そのものです。この Bean は org.springframework.oxm.castor.CastorMarshaller のインスタンスであり、基本的に Castor フレームワークをラップしています。先ほど触れたように、Spring の O/X 機能を利用するためにはサードパーティーの O/X フレームワークが必要です。ここでは Castor をサードパーティー製品として選択しています。また、castorMarshaller によって定義されるプロパティーがあることにも注意してください。このプロパティーは、Castor が Java Bean を XML 出力にマッピングするために、またその逆の処理を行う際に使用されるマッピング・ファイルです。このファイルは mapping.xml と呼ばれ、マッピングの実行時にクラスパスに存在していなければなりません。この mapping.xml ファイルの内容については、このすぐ後に説明します。

リスト 2 は、実際に O/X マッパーを実行するコード・リストの一部抜粋です。これを見るとわかるように、O/X マッパーを実行するクラスは非常に単純な Java クラスです。

リスト 2. OXMExample クラス (一部抜粋)
public class OXMExample {
    private static final String FILE_NAME = "simplebean.xml";
    private SimpleBean simpleBean;

    private Marshaller marshaller;
    private Unmarshaller unmarshaller;

    public void setMarshaller(Marshaller marshaller) {
        this.marshaller = marshaller;
    }

    public void setUnmarshaller(Unmarshaller unmarshaller) {
        this.unmarshaller = unmarshaller;
    }

    public void saveSimpleBean() throws IOException {
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(FILE_NAME);
            this.marshaller.marshal(simpleBean, new StreamResult(os));
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }

    public void loadSimpleBean() throws IOException {
        FileInputStream is = null;
        try {
            is = new FileInputStream(FILE_NAME);
            this.simpleBean 
                        = (SimpleBean) this.unmarshaller.unmarshal(new StreamSource(is));
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        ApplicationContext appContext 
                        = new ClassPathXmlApplicationContext("applicationContext.xml");
        OXMExample ex = (OXMExample) appContext.getBean("oxmExample");
        ex.go();
    }

    private void go() throws IOException {
        simpleBean = getSimpleBean();

        saveSimpleBean();
        loadSimpleBean();
        
        System.out.println("name: " + simpleBean.getName());
        System.out.println("job description: " + simpleBean.getJobDescription());
        System.out.println("age: " + simpleBean.getAge());
        System.out.println("executive: " + simpleBean.isExecutive());
    }


    private SimpleBean getSimpleBean() {
        SimpleBean simpleBean = new SimpleBean();
        simpleBean.setAge(35);
        simpleBean.setExecutive(false);
        simpleBean.setJobDescription("Janitor");
        simpleBean.setName("Mister Jones");

        return simpleBean;

    }
}

リスト 2 については、まず最初に実行される main メソッドを説明し、次にそれに続いて実行されるコードを説明することにします。

ます、コードは main メソッドの中で Spring のアプリケーション・コンテキストを取得します。これがリスト 1 で見た構成ファイルです。このファイルはクラスパスに存在していなければならず、存在しない場合には、このコードを実行すると例外が発生します。

アプリケーション・コンテキストを取得すると、構成ファイルの中の定義から OXMExample のインスタンスが作成されます。コードの中での、この Bean の名前 (oxmExample) が、構成ファイル (リスト 1) の中で定義されているとおりであることに注意してください。OXMExample のインスタンスを作成した後には、go() メソッドが呼び出されます。これは、既にコマンドラインから実行されているオブジェクトを Spring フレームワークがインスタンス化するという点で少し風変わりですが、ここではデモをするという目的のために、単純になるようにしています。

go() メソッドは以下の 3 つの処理を実行し、その結果のデータを出力します。

  1. SimpleBean のインスタンスを作成します。
  2. 次に、その作成されたインスタンスをマーシャリングします。
  3. 次に、マーシャリングによって作成された XML 文書をアンマーシャリングします。

ここでは getSimpleBean() メソッドを使用して、架空の従業員の情報を含む SimpleBean オブジェクトをインスタンス化しています。この情報には、年齢 (整数)、業務内容 (ストリング)、氏名 (ストリング)、その従業員が経営幹部かどうか (ブール値) が含まれています。getSimpleBean() メソッドでは、これらのフィールドにテスト・データを追加し、SimpleBean オブジェクトを呼び出し側 (この場合は go() メソッド) に返します。マーシャリングが実行される際には、この Bean の内容が XML ファイルに書き出され、アンマーシャリングが実行される際には、その XML ファイルの内容が読み取られます。

saveSimpleBean() メソッドはマーシャリングを実行します。まず、simplebean.xml を参照するFileOutputStream オブジェクトを取得します。次に、マーシャラー・オブジェクト (Spring の依存性注入によってインスタンス化されています) を使って marshal メソッドを呼び出します。このメソッドには下記の 2 つのパラメーターが必要です。

  • マーシャリング対象のオブジェクト (この場合は SimpleBean インスタンス)
  • StreamResult オブジェクト (基本的には XML 出力を抽象化したもの)

loadSimpleBean() メソッドはアンマーシャリングを実行します。まず、simplebean.xml を参照する FileInputStream オブジェクトを取得します。次に、アンマーシャラー・オブジェクト (Spring の依存性注入によってインスタンス化されています) を使って unmarshal メソッドを呼び出します。必要なパラメーターは、FileInputStream オブジェクトをラップする StreamSource オブジェクトのみです。アンマーシャリングによって汎用のオブジェクトが作成されることに注意してください。そのため、このオブジェクトを明示的に SimpleBean 型にキャストする必要があります。

OXMExample クラスと Spring の構成ファイルが用意できても、まだこのコードを実行する準備は整っていません。リスト 1 のマッピング・ファイルを覚えているでしょうか。ここでも、このマッピング・ファイル (リスト 3 に示します) を定義する必要があります。このファイルも、実行時にクラスパスに存在していなければなりません。

リスト 3. mapping.xml
<mapping>
        <class name="com.xyz.SimpleBean">

           <map-to xml="simplebean"/>

           <field name="age" type="integer">
              <bind-xml name="age" node="element"/>
           </field>

           <field name="executive" type="boolean">
              <bind-xml name="is-executive" node="element"/>
           </field>
	   
           <field name="jobDescription" type="string">
              <bind-xml name="job" node="element"/>
           </field>

           <field name="name" type="string">
              <bind-xml name="name" node="element"/>
           </field>
        </class>
</mapping>

リスト 3 のマッピング・ファイルは Castor での O/X マッピングの実装に特有のファイルです。最初の要素 (class) は、XML 出力にマッピングされるクラスを単純に定義しますが、フル・パスで指定する必要があります。

map-to 要素は XML ファイルのルート要素の名前を指定します。XML の仕様では、各 XML ファイルがルート要素を持たなければならないため、ルート要素の指定は重要です。

field 要素は SimpleBean クラスの特定のフィールドにマッピングされます。各 field 要素の bind-xml 子要素は、そのフィールドに関する XML 特有の情報 (対応する XML 要素の名前、各フィールドの値が要素の値なのか属性の値なのか、など) を指定するために使われます。ご覧のように、この場合はすべての値は要素の値です。

テスト

コーディングは終わりましたが、このアプリケーションを実行する前に一部の依存関係を解決する必要があります。

Spring 特有の依存関係は以下のとおりです。

  • org.springframework.asm-3.0.0.M4.jar
  • org.springframework.beans-3.0.0.M4.jar
  • org.springframework.context-3.0.0.M4.jar
  • org.springframework.core-3.0.0.M4.jar
  • org.springframework.expression-3.0.0.M4.jar
  • org.springframework.oxm-3.0.0.M4.jar

Castor 特有の依存関係は以下のとおりです。

  • castor-1.3-core.jar
  • castor-1.3-xml.jar

また、commons-logging-1.1.1.jar と log4j-1.2.15.jar も必要です。この 2 つを Spring フレームワークでは必要とするからです。

これらの JAR (Java Archive) ファイルはすべて、実行時にクラスパスに存在していなければなりません。これらの依存関係がない状態でコードを実行しようとすると、多くの場合、特定のクラスが見つからないという例外が発生します。そうした例外が発生した場合には、必要な依存関係がすべてクラスパス上にあることを再度確認します。実際、このコードを適切にコンパイルするためには、これらの JAR ファイルのほとんどが必要です。これらの JAR ファイルの入手に関しては、この記事の最後にある「参考文献」を参照してください。

日頃からお使いの IDE を使って、あるいは単純にコマンドラインを使って、OXMExample.class を実行します。コマンドラインから実行する場合には、単純に作業ディレクトリーから type java -cp [classpath] OXMExample と入力します (ここで [classpath] は、上で説明したすべての依存関係 (JAR ファイルと構成ファイル) を参照するクラスパスです)。

このコマンドを初めて実行した後に、simplebean.xml という新しいファイルがカレント作業ディレクトリーに作成されるはずです。このファイルの内容はリスト 4 と一致するはずです。

リスト 4. simplebean.xml ファイル
<?xml version="1.0" encoding="UTF-8"?>
<simplebean>
 <age>35</age>
 <is-executive>false</is-executive>
 <job>Janitor</job>
 <name>Mister Jones</name>
</simplebean>

リスト 4 は、アプリケーションのマーシャリングを実行した結果の出力を表していますが、アプリケーションのアンマーシャリングを実行した結果もコンソールに表示されるはずです。この出力はリスト 5 のようになっているはずです。

リスト 5. アンマーシャリングの出力
name: Mister Jones
job description: Janitor
age: 35
executive: false

これで完成です。Spring O/X マッピングの最初のテストが無事に成功しました。おめでとうございます!

今度は開発者として皆さんが最善をつくす番です。コードをいじり、クラスにフィールドを追加して、それらのフィールドを XML ファイルにマッピングしてみてください。あるいは一部のフィールドを削除し、それらのフィールドを XML ファイルから削除してみてください。Castor のドキュメントを調べ、より複雑なこと、例えばネストされた要素なども試してみてください。可能性は無限です。

まとめ

Spring O/X マッピングは Spring フレームワークに追加された強力なインターフェースです。O/X マッピングを使用することで、XML 文書を Java オブジェクトに変換することができ、また Java オブジェクトを XML 文書に変換することもできます。

Spring O/X マッピングは、Spring の重要なメリットである依存性注入を利用しています。依存性注入を Spring の O/X マッパーと組みあわせると、さまざまな形式の O/X 実装 (Castor、XBeans、JiBX、JAXB、XStream など) のいずれかを利用して容易にソリューションを作成することができます。選択された特定の実装は Spring の強力な「制御の反転」コンテナーの一部であるため、コードを変更せずに特定の O/X 実装同士を簡単に切り換えることができます。

また Spring の O/X マッパーの例外の階層構造は一貫性を持っています。これはつまり、どのようなサードパーティーの実装を選択した場合にも、スローされるランタイム例外は同じだということです。この点からも、O/X ベンダーの切り替えを容易に行うことができます。

Java アプリケーションでの XML サポートに対するニーズは高く、また Java 開発コミュニティーの至る所で Spring フレームワークが盛んに使われていることから、Spring に O/X マッパーが追加されたことは世界中の Java アプリケーション開発者にとって歓迎すべきことです。


ダウンロード

内容ファイル名サイズ
The source files used in this articleOXMTest.zip4KB

参考文献

学ぶために

  • Castor とその機能について学ぶために、4 回シリーズの記事「Castor によるデータ・バインディング」(Brett McLaughlin、developerWorks、2007年11月から 2008年4月) を読んでください。インストールとセットアップ、Java と XML のコードのマーシャリングとアンマーシャリング、スキーマ間のマッピング、Java オブジェクトと SQL データ・ストアとのバインディングなどが解説されています。
  • 4 回シリーズの記事、「The Spring series」(Naveen Balani、developerWorks、2005年6月から10月) は Spring フレームワークの可能性を探っています。
  • XML および関連技術において IBM 認定技術者になる方法については、IBM XML certification を参照してください。
  • developerWorks の XML ゾーンを XML の技術ライブラリーとして利用してください。広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、IBM Redbooks などが用意されています。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • developerWorks podcasts ではソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Java technology
ArticleID=446974
ArticleTitle=Spring での Object/XML マッピングのサポートを探る
publish-date=10202009