Simple は XML シリアライズ/デシリアライズのプロセスを単純化するために使われる Java フレームワークです。Simple を使用すると、POJO (Plain Old Java Object) を XML 文書に変換するプロセス (シリアライズと呼ばれます) を単純化することができます (まさに Simple (単純) という名前どおりです)。また Simple は、その逆、つまり XML 文書を POJO に変換することもできます (このプロセスはデシリアライズと呼ばれます)。
Simple は、シリアライズとデシリアライズにアノテーションを使用することで、このプロセスを Simple という名前どおりに単純化しています。POJO には、そのオブジェクトに対応する XML 文書の表示方法を指定するアノテーションが追加されます。一部のフィールドはアノテーションによって属性として指定されます。それ以外のフィールドはアノテーションによって要素として指定されます。クラスは通常、アノテーションによってルート要素として指定されます。Simple フレームワークは、シリアライズ・プロセスの際のアノテーションの解釈や、対応する XML 文書の生成という退屈なプロセスを処理します。当然のことですが、これらのアノテーションの解釈は、XML 文書が POJO に変換されるデシリアライズ・プロセスの際にも行われます。
Simple を使用すると、いくつかのメリットがもたらされます。第 1 に、Simple を使うことでアプリケーションの開発が迅速になります。Simple は非常に単純であるため、Simple を使うことで、XML シリアライズ/デシリアライズを使用する堅牢なアプリケーションを素早く実装することができ、そのための学習に過度の時間を掛ける必要がなく、開発のオーバーヘッドもなくなります。
次に、Simple には構成が必要ありません。先ほど触れたように、Simple はアノテーションを使用します。これらのアノテーションが、この種のフレームワークにつきものの、XML ベースの構成ファイルの代わりをするのです。
最後に、アプリケーションに Simple を使用することで増加するフットプリントは、ほんのわずかです。JAR (Java Archive) ファイルは 239 キロバイトにすぎません。また Simple は、他の競合するフレームワークでよく見られるケースとは異なり、他の一連の JAR ファイルに依存することはありません。
Simple を使用するには、まず Simple を入手する必要があります。そのためには、「参考文献」に挙げた Simple の Web サイトを訪れ、アーカイブをダウンロードします。ただし、このプロセスには良い点と困った点があります。良い点は、このアーカイブが無料であることです。困った点は、このアーカイブが .tar.gz 形式であることです。この .tar.gz 形式のアーカイブを開くために Microsoft® Windows® ネイティブのアーカイブ展開プログラムを使用すると、ファイルを展開することができずに落胆するかもしれません。そうした場合には WinZip などのアーカイブ・ユーティリティーが必要です。
このアーカイブ・ファイルを展開したら、jar ディレクトリーの中に、当然ながら JAR ファイル (simple-xml-2.1.4.jar) があることに注意してください。コンパイル時と実行時には、この JAR ファイルがクラスパスに存在する必要があります。
オブジェクトを XML 文書にシリアライズするプロセスは (驚いたことに) 単純です。このプロセスには 2 つのステップがあります。
- 適切なアノテーションを付けられた POJO を作成します。
- 実際にシリアライズ・プロセスを実行する数行のコードを作成します。
この記事では、おなじみの (私の記事の読者にはおなじみの、という意味です) テーマである、釣り用のルアー (lure) の例を再度使用します。リスト 1 はルアーに関する情報を表現する POJO です。
リスト 1. Lure クラス
@Root
public class Lure {
@Attribute
private String type;
@Element
private String company;
@Element
private int quantityInStock;
@Element
private String model;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public int getQuantityInStock() {
return quantityInStock;
}
public void setQuantityInStock(int quantityInStock) {
this.quantityInStock = quantityInStock;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
|
この POJO にはまったく複雑なところはありません。一見、見慣れないように思える唯一の部分は、アノテーションです。このようにしているのは意図的であり、Simple フレームワークが名前どおりに単純なはずであることを思い出してください。
@Root アノテーションは、この XML 文書のルート要素を表します。すべての XML 文書にはルート要素が必要なため、このアノテーションを含めることは重要です。
type フィールドの上にある @Attribute アノテーションは、このフィールドが属性であることを示しています。この属性はルート要素の属性として追加されています。
それ以外のアノテーションは @Element アノテーションです。このアノテーションは、company、quantityInStock、model という 3 つのフィールドの真上にあります。これらのフィールドは、XML 文書の中の要素を表します。
それ以外の POJO は JavaBean 標準に従うアクセサーとミューテーターで構成されています。
これで POJO が完成したので、今度はシリアライズ用のコードを作成します。そのコードがリスト 2 です。
リスト 2. LureExample クラス
public static void main(String[] args) {
try {
Serializer serializer = new Persister();
Lure lure = new Lure();
lure.setCompany("Donzai");
lure.setModel("Marlin Buster");
lure.setQuantityInStock(23);
lure.setType("Trolling");
File result = new File("lure.xml");
serializer.write(lure, result);
} catch (Exception e) {
e.printStackTrace();
}
}
|
まず、Persister オブジェクトをインスタンス化します。このクラスが Simple フレームワークの一部であり、Serializer インターフェースを実装していることに注意してください。
次に、Lure オブジェクトをインスタンス化し、各フィールドを適切に設定します。この場合、ルアーを製造するメーカーの名前は Donzai であり、モデルの名前は Marlin Buster、在庫の数は 23、そしてルアーのタイプは Trolling です。
続いて、File オブジェクトを、XML 文書となるファイルの名前を付けてインスタンス化します。この場合、その XML 文書の名前は lure.xml です。
最後に、シリアライザーを呼び出し、ファイルを書き出します。write() メソッドには 2 つのパラメーターが指定されています。最初のパラメーターは POJO で、2 番目のパラメーターは File オブジェクトです。
では、このコードを実行します。リスト 2 は Java アプリケーションです。そのため、このアプリケーションを適当な IDE (統合開発環境) を使って実行することができます。simple-xml-2.1.4.jar がクラスパスにあることを確認してください。Eclipse を使用している場合には、このファイルを単純に右クリックして「Run As (実行)」を選択し、表示されるメニューから「Java Application (Java アプリケーション)」を選択します。
すべてが順調に動作すると (順調に動作したはずです。先ほどシリアライズのプロセスは単純でもあると言ったことを思い出してください)、作成される XML 文書はリスト 3 のようになるはずです。
リスト 3. LureExample の出力
<lure type="Trolling"> <company>Donzai</company> <quantityInStock>23</quantityInStock> <model>Marlin Buster</model> </lure> |
リスト 3 に関して、注意する点が 2 つあります。第 1 に、lure type がルート要素の属性であることに注意してください。これは至極妥当なことです。POJO の type フィールドには @Element ではなく @Attribute というアノテーションを追加したからです。
作成された XML に関する、もう 1 つの重要な点として、要素名が JavaBean 標準に従っています。例えば、クラス名は Lure ですが、ルート要素は lure です。3 つの子要素名はフィールド名と完全に対応しています。これも実際的です。ルート要素の名前の大文字/小文字が適切であるのに子要素の名前が別のパターンに従うようでは困るからです。
オブジェクトのシリアライズは非常に容易なので、オブジェクトのデシリアライズも容易なはずだと思いませんか?その通りなのです。
デシリアライズが XML 文書を POJO に変換するプロセスであることを思い出してください。幸いなことに、その XML 文書として、先ほど作成した XML 文書が使えるのです。
リスト 4 はデシリアライズのコードを示しています。
リスト 4. LureExample2 クラス
public static void main(String[] args) {
try {
Serializer serializer = new Persister();
File source = new File("lure.xml");
Lure lure = serializer.read(Lure.class, source);
System.out.println(lure.getCompany());
System.out.println(lure.getModel());
System.out.println(lure.getQuantityInStock());
System.out.println(lure.getType());
} catch (Exception e) {
e.printStackTrace();
}
}
|
この場合もリスト 2 と同様に、Serializer インターフェースを実装するオブジェクト (Persister) をインスタンス化することから始めます。
次の行もリスト 2 で見たような行で、File オブジェクトのインスタンス化を行っています。ただし、この場合は、リスト 2 とは明確な違いがあります。リスト 2 では、存在しないファイルの File オブジェクトをインスタンス化しましたが、このリスト 4 では、ファイルが実際に存在することを前提としています (そして実際にファイルが存在する必要があります)。
次に、Serializer オブジェクトから read メソッドを呼び出して POJO をインスタンス化します。read メソッドは引数として、POJO のクラスと、データを含む XML ファイルを表現する File オブジェクトの 2 つをとります。
最後に、POJO からすべての情報を出力し、すべての情報が適切に読み取られたことを確認します。
このコードを実行すると、出力はリスト 5 のようになるはずです。
リスト 5. LureExample2 の出力
Donzai Marlin Buster 23 Trolling |
ここまでの段階では、シリアライズ/デシリアライズの対象とした XML 文書は非常に単純でした。
しかし大多数の XML 文書は遥かに複雑で、何階層にもネストされた要素があるのが普通です。場合によると、繰り返し要素が 1 つまたは多数あり、その各要素にいくつかの子要素があります。
幸いなことに、より複雑な文書の場合にも、Simple を使うことで名前どおりに作業が単純になります。単純に POJO の中に POJO をネストさせるだけでよいのです。リスト 6 を見てください。
リスト 6. AdvancedLure クラス
@Attribute private String type; @Element private String company; @Element private int quantityInStock; @Element private String model; @Element private ConfigurationScheme configurationScheme; |
リスト 6 の AdvancedLure クラスは、リスト 1 で説明した Lure クラスと驚くほど似ています。1 つの例外は、configurationScheme という追加のフィールドが含まれていることです。構成の仕組み (configuration scheme) は別の POJO (リスト 7) によって表現されます。
リスト 7. ConfigurationScheme クラス
@Root
public class ConfigurationScheme {
@Element
private String color;
@Element
private int size;
|
簡潔にするために、アクセサーとミューテーターは省略しました。
リスト 7 のアノテーションはおなじみのはずです。これらのアノテーションは、リスト 1 で使用したものと同じです。
これに続いて、リスト 8 が登場します。
リスト 8. LureExample3 クラス
public static void main(String[] args) {
try {
Serializer serializer = new Persister();
AdvancedLure lure = new AdvancedLure();
lure.setCompany("Donzai");
lure.setModel("Marlin Buster");
lure.setQuantityInStock(23);
lure.setType("Trolling");
ConfigurationScheme configurationScheme = new ConfigurationScheme();
configurationScheme.setColor("Blue");
configurationScheme.setSize(3);
lure.setConfigurationScheme(configurationScheme);
File result = new File("advancedlure.xml");
serializer.write(lure, result);
} catch (Exception e) {
e.printStackTrace();
}
}
|
リスト 8 がリスト 2 と大きく異なる点は、リスト 8 では ConfigurationScheme オブジェクトをインスタンス化し、AdvancedLure オブジェクトの適切なフィールドを設定している点です。
このコードを実行すると、出力はリスト 9 のようになるはずです。
リスト 9. LureExample3 の出力
<advancedLure type="Trolling">
<company>Donzai</company>
<quantityInStock>23</quantityInStock>
<model>Marlin Buster</model>
<configurationScheme>
<color>Blue</color>
<size>3</size>
</configurationScheme>
</advancedLure>
|
これを見るとわかるように、ネストされた要素はまさに期待したとおりにシリアライズされています。
XML 文書の中に特定の要素の列挙が含まれていることがよくあります。つまり同じ要素名が繰り返され、ただし子や属性データが異なるような場合です。幸いなことに、Simple はこうした状況にも対処することができます。
この機能を説明するために、Inventory という新しいクラスを作成します。このクラスには、在庫が保管されている倉庫の名前と、その在庫の場所にあるルアーのリストが含まれています。
リスト 10. Inventory クラス
@Root
public class Inventory {
@ElementList
private List<AdvancedLure> lures;
@Attribute
private String warehouse;
|
@ElementList という新しいアノテーションが使われていることに注意してください。このアノテーションは Simple フレームワークに対して、このアノテーションに対応する List オブジェクトが XML 要素の列挙を表すことを伝えています。
この POJO のシリアライズを説明するために使用したコードは、もっとコンパクトな POJO (例えばリスト 2 でシリアライズされたオブジェクトなど) をシリアライズするために使用したコードと同じくらい容易です。先ほどよりも複雑になっているのは、テスト用に必要なオブジェクトをすべてインスタンス化しているためです。リスト 11 を見てください。
リスト 11. LureExample4 クラス
Serializer serializer = new Persister();
AdvancedLure lure = new AdvancedLure();
lure.setCompany("Donzai");
lure.setModel("Marlin Buster");
lure.setQuantityInStock(23);
lure.setType("Trolling");
ConfigurationScheme configurationScheme = new ConfigurationScheme();
configurationScheme.setColor("Blue");
configurationScheme.setSize(3);
lure.setConfigurationScheme(configurationScheme);
AdvancedLure lure2 = new AdvancedLure();
lure2.setCompany("Ziggi");
lure2.setModel("Tuna Finder");
lure2.setQuantityInStock(44);
lure2.setType("Trolling");
ConfigurationScheme configurationScheme2 = new ConfigurationScheme();
configurationScheme2.setColor("Red");
configurationScheme2.setSize(5);
lure2.setConfigurationScheme(configurationScheme2);
List<AdvancedLure> lures = new ArrayList<AdvancedLure>();
lures.add(lure);
lures.add(lure2);
Inventory inventory = new Inventory();
inventory.setLures(lures);
inventory.setWarehouse("Midwest");
File result = new File("inventory.xml");
serializer.write(inventory, result);
|
このコードが実行されると、inventory.xml という XML ファイルが作成されます。このファイルの内容はリスト 12 のようなもののはずです。
リスト 12. LureExample4 の出力
<inventory warehouse="Midwest">
<lures>
<advancedLure type="Trolling">
<company>Donzai</company>
<quantityInStock>23</quantityInStock>
<model>Marlin Buster</model>
<configurationScheme>
<color>Blue</color>
<size>3</size>
</configurationScheme>
</advancedLure>
<advancedLure type="Trolling">
<company>Ziggi</company>
<quantityInStock>44</quantityInStock>
<model>Tuna Finder</model>
<configurationScheme>
<color>Red</color>
<size>5</size>
</configurationScheme>
</advancedLure>
</lures>
</inventory>
|
これを見るとわかるように、この出力はリスト 11 でインスタンス化して作成した POJO をそのまま写したようなものです。2 つの advancedLure 要素があり、それぞれの要素には、その要素に対応する POJO に追加するために使われたデータが含まれています。ネスト関係も適切であることに注意してください。
コードの中で、不変の POJO を使用している場合もあります。この場合には、フィールドのプロパティーを変更するためのセッター・メソッドがなく、代わりにこれらの値を設定するコンストラクターに頼ることになる可能性もあります。Simple は、この状況にも対処することができます。
この場合、アノテーションは、フィールド名の上ではなくコンストラクターの引数の中で指定されます。またアノテーションは、該当するアクセサー・メソッドの上にも必要です。リスト 13 を見てください。
リスト 13. Inventory2 クラス
public Inventory2(@ElementList(name="lures") List<AdvancedLure> lures,
@Attribute(name="warehouse") String warehouse) {
this.lures = lures;
this.warehouse = warehouse;
}
@ElementList(name="lures")
public List<AdvancedLure> getLures() {
return lures;
}
@Attribute(name="warehouse")
public String getWarehouse() {
return warehouse;
}
|
コンストラクターの引数の一部としてアノテーションを指定する場合には、そのアノテーションに対応するフィールド名も指定する必要があることに注意してください。最初の引数の場合、フィールド名は lures です。2 番目の引数の場合、フィールド名は warehouse です。
次に、対応するアノテーションとフィールド名をアクセサー・メソッドの上に配置します。lures のゲッターの真上に該当するアノテーションがありますが、このアノテーションはコンストラクターに使用されたアノテーションと完全に一致します。同様に、warehouse に対するゲッターの上にあるアノテーションは、そのアノテーションと完全に一致します。
このコードを実行するためには、リスト 11 を少しだけ変更し、リスト 14 のコードを含めるようにします。
リスト 14. LureExample5 クラス
Inventory2 inventory = new Inventory2(lures,"MidWest"); |
リスト 11 で使用したセッター・メソッドの代わりに、リスト 14 のコードを使用することができます。それ以外はすべて同じです。
Simple には、もう 1 つの素晴らしい機能があり、XML 文書をデシリアライズする際にテンプレート・フィルターまたはデフォルト値を使うことができます。
オリジナルの lure.xml に戻り、リスト 15 のように少し修正します。
リスト 15. Lure2.xml 文書
<lure type="Trolling">
<company>${lure.company}</company>
<quantityInStock>23</quantityInStock>
<model>Marlin Buster</model>
</lure>
|
company 要素には実際の会社の名前が含まれておらず、Apache Ant 風の変数宣言が含まれていることに注目してください。この場合、変数の名前は lure.company です。
テンプレート・フィルターを使うと、こうした変数宣言を、実行時に確立される実際の値で置き換えることができます。それを簡単に行う方法として、変数名を変数値と関連付ける Map オブジェクトを使う方法があります。すると、その Map オブジェクトを使って Simple フレームワークから Filter オブジェクトを作成することができます。そしてその Filter オブジェクトを使って Persister オブジェクトを作成します。リスト 16 を見てください。
リスト 16. LureExample6 クラス
Map<String,String> map = new HashMap<String,String>();
map.put("lure.company", "Monmouth");
Filter filter = new MapFilter(map);
Serializer serializer = new Persister(filter);
File source = new File("lure2.xml");
Lure lure = serializer.read(Lure.class, source);
System.out.println(lure.getCompany());
System.out.println(lure.getModel());
System.out.println(lure.getQuantityInStock());
System.out.println(lure.getType());
|
リスト 16 は、リスト 2 とそれほど違わないように見えます。主な違いは、String 値を String キーに関連付ける HashMap がインスタンス化されている点です。この場合の String キーはご想像どおり lure.company であり、これはリスト 15 で使用した変数名です。ここでは、値として Donzai ではなく Monmouth を指定していますが、これは先ほど読みとった XML 文書の中にある値です。
このコードを実行すると、出力はリスト 17 のようになります。
リスト 17. LureExample6 出力
Monmouth Marlin Buster 23 Trolling |
これを見るとわかるように、テンプレート・フィルターは lure.company という変数名を、そのキー名と関連付けされた、Map オブジェクトの中の実際の値で置き換えています。出力は完全に予想したとおりです。
この記事で見てきたように、Simple は XML シリアライズ/デシリアライズのための堅牢なフレームワークです。Simple は使いやすく、構成を何も必要とせず、そして開発を効率化します。
Simple には他にも強力な機能が数多くあります。しかしスペースの制約から、ここではその一部のみを紹介しました。ソフトウェア開発作業の中で XML シリアライズ/デシリアライズを必要とする開発者には、Simple を検討してみることを強くお勧めします。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Source code for the examples used in this article | Simple.zip | 5KB | HTTP |
学ぶために
- XML を扱い始めたばかりの方は、w3schools.com の XML Tutorial を試してみてください。
- Java プログラミング言語を扱い始めたばかりの方は、The Java Tutorials に提供されている資料を活用してください。
- 「新たに使い始める人のための XML の基礎: 適切なマークアップへの入門」(Kay Whatley 著、developerWorks、2009年2月) を読んでください。この記事では、XML を扱うのが初めての人のために、XML 文書の基本的な構造と、整形式の XML 文書を作成するために従うべきルール (命名規則、タグを適切にネストさせる方法、属性に関する指針、宣言、実体など) について紹介しています。また DTD とスキーマの使い方をとおして妥当性検証についても理解することができます。
- 「Introduction to XML」(Doug Tidwell 著、developerWorks、2002年8月) を読み、XML とは何か、なぜ XML が開発されたかを学んでください。このチュートリアルでは、XML に関する多様で重要なプログラミング・インターフェースや標準について説明し、そして企業がどのように XML を使用してビジネスの問題を解決するかを示す 2 つの事例研究で締めくくっています。
- 「New to Java programming」を訪れ、Java 技術の基本、また Java 技術を最近のソフトウェア開発にどう活用するかの概要を理解してください。このサイトのリンクから、developerWorks に掲載された入門的な関連資料や、他の教育資料、そして IBM からダウンロードできる資料や製品について調べてください。
- New to XML を訪れてください。このサイトは IBM developerWorks で XML 開発者に提供されているリソースを得るための素晴らしい出発点です。
- XML および関連技術において IBM 認定技術者になる方法については、IBM XML certification を参照してください。
- developerWorks の XML ゾーンを XML の技術ライブラリーとして利用してください。広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、IBM Redbooks などが用意されています。
- developerWorks の Technical events and webcasts: これらのセッションで最新情報を入手してください。
- developerWorks podcasts ではソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
製品や技術を入手するために
- Simple をダウンロードし、Simple の詳細を学んでください。
- Eclipse の Web サイトから Eclipse をダウンロードしてインストールしてください。
- IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。
議論するために
- ディスカッション・フォーラムに参加してください。
- XML zone discussion forums に参加してください。これらのフォーラムでは XML を中心に議論が行われています。
- developerWorks blogs からdeveloperWorks コミュニティーに加わってください。
