今週は,今までとは逆にJavaのクラスからXMLのスキーマを生成することを考えてみます。とはいうものの,Javaのソースだけではちょっと難しいのです。

たとえば,次のJavaのクラスをXMLに変換することを考えてみましょう。

public class Name {
    String first;
    String last;

        ....
}

今まで,スキーマからJavaのクラスを生成していた経験から,ルートタグがクラス名に相当することは分かります。では,フィールドは?

<name first="Yuichi" last="Sakuraba" />

このように属性として表すのでしょうか,もしくは次のようにタグとして表すのでしょうか。

<name>
  <first>Yuichi</first>
  <last>Sakuraba</last>
</name>

答えは,どちらでもかまわないです。

JavaとXMLが表せる範囲
図1 JavaとXMLが表せる範囲

より正確に言うならば,Javaのソースだけでは,フィールドをどのようにXMLに対応づけさせるかを指定できない,ということです。

Javaはオブジェクトをベースとしたオブジェクトモデルによって表記をおこないます。それに対し,XMLはツリー構造をベースとした文章モデルによって表記を行ないます。この2つのモデルでは表せる範囲が異なるため,変換ができない部分が残ります。

このように表せる範囲が異なるために発生する不整合をインピーダンスミスマッチといいます(図1)。

インピーダンスミスマッチを解消させるためには,Javaのソースコード以外の手段を使用せざるをえません。

そこで登場するのがアノテーションです。

たとえば,フィールドがXMLドキュメントに変換したときに属性になる場合@XmlAttributeで修飾し,タグになる場合@XmlElementで修飾するようにしてみましょう。

public class Name {
    @XmlAttribute
    String first;
    
    @XmlAttribute
    String last;

        ....
}

このように@XmlAttributeで修飾されていれば,XMLドキュメントは次のようになると分かります。

<name first="Yuichi" last="Sakuraba" />
アノテーションで表す範囲
図2 アノテーションで表す範囲

つまり,Javaでは表現できない領域をアノテーションを用いることでカバーし,インピーダンスミスマッチを解消しているのです(図2)。

ここで,xjcで生成したJavaのクラスを思いだしてください。今まで無視していましたが,生成したクラスにはアノテーションが付加されています。このアノテーションによって,Javaとスキーマの相互変換が可能になるのです。

それでは,JAXBが使用するアノテーションを紹介していきましょう。

JAXBで使用するアノテーションはjavax.xml.bin.annotationパッケージで定義されており,全部で29種類あります。

以下,主なアノテーションを用途ごとに示します。

クラスを修飾するアノテーション

クラスに使用できるAnnoationは表1に示した4種類です。

表1 クラスを修飾するアノテーション
アノテーション名 説明/デフォルト値
@XmlType クラスをスキーマの型に対応づける
@XmlType(
  name="##default",
  propOrder={""},
  namespace="##default",
  factoryClass=DEFAULT.class,
  factoryMethod=""
)
@XmlRootElement クラスをスキーマの宣言に対応づける
@XmlRootElement(
  name="##default",
  namespace="##default"
)
@XmlAccessorType フィールド,プロパティの対応を決定する
@XmlAccesorType(
  namespace="http://www.w3.org/2001/XMLSchema",
  type=DEFAULT.class
)
@XmlAccessorOrder フィールド,プロパティの対応順序を決める
なし