「そんなに早くないよ、若者!あと 2 つレッスンがあるよ!」

「2つ? わあ。まあ、分かった。自分のカッコよさをさらに高めるために何をしませんか! 私はすべて耳を傾けています。」

「JSON と同様、XML は、異なるプログラムやコンピューター間でデータを受け渡すときによく使用されます。また、Java プログラマーが XML を扱う際の作業を大幅に簡素化するフレームワークがいくつかあります。今日はそのうちの 1 つを紹介します。」

「JAXB は、XML を操作するための優れた多目的フレームワークです。」

JAXB-1

「JAXB は JDK の一部であるため、個別にダウンロードする必要はありません。」

「まず使用方法の例を示してから、それを分析します。たとえば、次のとおりです。」

オブジェクトをXMLに変換する
public static void main(String[] args) throws JAXBException
{
 // Create an object to be serialized into XML
 Cat cat = new Cat();
 cat.name = "Missy";
 cat.age = 5;
 cat.weight = 4;

 // Write the result of the serialization to a StringWriter
 StringWriter writer = new StringWriter();

 // Create a Marshaller object that will perform the serialization
 JAXBContext context = JAXBContext.newInstance(Cat.class);
 Marshaller marshaller = context.createMarshaller();
 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
 // And here's the serialization itself:
 marshaller.marshal(cat, writer);

 // Convert everything written to the StringWriter
 String result = writer.toString();
 System.out.println(result);
}
オブジェクトを XML に変換するクラス
@XmlType(name = "cat")
@XmlRootElement
public class Cat
{
 public String name;
 public int age;
 public int weight;

 public Cat()
 {
 }
}
シリアル化の結果と画面出力:
<猫
> <名前>ミッシー</name> 
<年齢> 5 </年齢> 
<体重> 4 < /体重> < 
/猫>

「どういうわけか、行ごとに、このコードは JSON シリアル化を思い出させます。同じアノテーションですが、JSON では ObjectMapper が使用され、これでは Context と Marshaller が使用されます。」

「そうです。本当によく似ています。ジャクソンは JAXB をモデルにしました。しかし、JAXB もどこかからコピーされたものです。ゼロから天才的なものを発明することはできません。」

「そのようですね。」

「OK、何が起こっているのか:」

「4 行目から 7 行目では、 Catオブジェクトを作成し、それにデータを設定します。」

10 行目では、結果を書き込むための Writer オブジェクトを作成します。

「13 行目で、「コンテキスト」を作成します。これは ObjectMapper に似ていますが、そこから 2 つの追加の子オブジェクトが作成されます。Marshaller はシリアル化用で、Unmarshaller は逆シリアル化用です。Jackson とは小さな違いがありますが、違いはありませ。根本的には違いません。」

「14 行目で、Marshallerオブジェクトを作成します。マーシャリングはシリアル化と同義です。」

「15 行目では、FORMATTED_OUTPUT プロパティを TRUE に設定します。これにより、結果に改行とスペースが追加され、コードが人間が判読できるようになり、すべてのテキストが 1 行に収まるようになります。」

「17 行目で、オブジェクトをシリアル化します。」

20~21行目ではシリアル化の結果を画面に表示しています。

「@XmlType(name = 'cat&') および @XmlRootElement アノテーションとは何ですか?」

" @XmlRootElement は、このオブジェクトが XML 要素の「ツリーのルート」になる可能性があることを示します。言い換えると、このオブジェクトは最上位の要素になることができ、他のすべての要素を含めることができます。"

" @XmlType(name = 'cat') は、クラスが JAXB シリアル化に関与していることを示し、このクラスの XML タグの名前も指定します。

「それでは、XML 逆シリアル化の例を示します。」

XMLからオブジェクトを変換する
public static void main(String[] args) throws JAXBException
{
 String xmldata = "<cat><name>Missy</name><age>5</age><weight>4</weight></cat>";
 StringReader reader = new StringReader(xmldata);

 JAXBContext context = JAXBContext.newInstance(Cat.class);
 Unmarshaller unmarshaller = context.createUnmarshaller();

 Cat cat = (Cat) unmarshaller.unmarshal(reader);
}
オブジェクトが XML から逆シリアル化されるクラス
@XmlType(name = "cat")
@XmlRootElement
public class Cat
{
 public String name;
 public int age;
 public int weight;

 public Cat()
 {
 }
}

「すべてはジャクソンの場合とほぼ同じです。しかし、念のため、ここで起こっていることをすべて説明します。」

「3 行目では、逆シリアル化する XML を格納する文字列を渡します。」

「4 行目では、XML 文字列をStringReaderでラップしています。」

「6 行目では、クラスのリストを渡すJAXB コンテキストを作成します。」

「7 行目で、 Unmarshaller、つまり逆シリアル化を実行するオブジェクトを作成します。」

「9 行目で、リーダー オブジェクトから XML を逆シリアル化し、Cat オブジェクトを取得します。」

「今ではすべてがほぼ明白に思えます。しかし、数時間前、私はそれがどのように機能するかを理解するために頭を悩ませていました。」

「賢くなるといつもそうなります。複雑なものは単純になります。」

「賢くなった?嬉しくて仕方ない」。

「素晴らしいですね。JAXB シリアル化の結果を制御するために使用できるアノテーションのリストは次のとおりです。」

JAXB アノテーション 説明
@XmlElement(名前) 畑の近くに設置。
フィールドは XML 要素に保存されます。
タグの名前を設定できます。
@XmlAttribute(名前) 畑の近くに設置。
フィールドは XML 属性として保存されます。
属性の名前を設定できます。
@XmlElementWrapper(nillable = true) 畑の近くに設置。
要素のグループに「ラッパー タグ」を設定できます。
@XmlType 教室の近くに設置されています。
デフォルトのコンストラクターがプライベートである場合に、オブジェクトを作成するメソッドを指定できます。
@XmlJavaTypeAdapter 畑の近くに設置。
フィールドを文字列に変換するクラスを指定できます。

「興味深いですね! でも、これらの注釈を使用する例を教えていただけますか? 説明は別の話ですが、実際に動作する例は別の話です。」

「わかりました。例を示します。JAXB ではフィールドの代わりに getter/setter メソッドに注釈を付けることができることを付け加えておきたいと思います。」

「これが私が約束した例です。」

オブジェクトをXMLに変換する
public static void main(String[] args) throws JAXBException
{
 // Create Cat and Zoo objects to be serialized into XML
 Cat cat = new Cat();
 cat.name = "Missy";
 cat.age = 5;
 cat.weight = 4;

 Zoo zoo = new Zoo();
 zoo.animals.add(cat);
 zoo.animals.add(cat);

 // Write the result of the serialization to a StringWriter
 StringWriter writer = new StringWriter();

 // Create a Marshaller object that will perform the serialization
 JAXBContext context = JAXBContext.newInstance(Cat.class, Zoo.class);
 Marshaller marshaller = context.createMarshaller();
 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
 // Here's the serialization itself
 marshaller.marshal(zoo, writer);

 // Convert everything written to the StringWriter into a String
 System.out.println(writer.toString());
}
オブジェクトを XML に変換するクラス
@XmlType(name = "zoo")
@XmlRootElement
public class Zoo
{
 @XmlElementWrapper(name = "wild-animals", nillable = true)
 @XmlElement(name = "tiger")
 public List<Cat> animals = new ArrayList<>();
}

public class Cat
{
 @XmlElement(name = "catname")
 public String name;
 @XmlAttribute(name = "age")
 public int age;
 @XmlAttribute(name = "w")
 public int weight;

 public Cat()
 {
 }
}
シリアル化の結果と画面出力:
<動物園
> <野生動物
> <虎の年齢 = "5" w = "4"> 
<猫名>ミッシー</猫名> </タイガー> 
<
虎の年齢 = "5" w = "4"> <
猫名>ミッシー</猫名> < 
/タイガー> < 
/野生動物> 
</動物園>

「今回は Cat オブジェクトをシリアル化しているのではなく、Cat オブジェクトのコレクションを格納する Zoo オブジェクトをシリアル化していることに注意してください。」

「cat オブジェクトはコレクションに 2 回追加されたため、XML に 2 回含まれています。」

「このコレクションには、コレクションのすべての要素をラップする独自の ' wild-animals ' タグがあります。」

年齢と体重の要素は、年齢とw w 属性になりました。」

@XmlElement属性を使用して、猫タグを虎タグに変更しました。」

「17 行目に注目してください。ここでは 2 つのクラス ( ZooCat ) を JAXB コンテキストに渡します。これらは両方ともシリアル化に関与しているためです。」

「今日はとても興味深い一日でした。新しい情報がたくさんありました。」

「はい。うれしく思います。では、少し休憩して、続けましょう。」