JAXBの簡単な解説(2)

前回はまず使ってみるということで、単純なJavaオブジェクトからXMLへ変換する方法を解説しました。

今回は、XMLからJavaオブジェクトへ変換する方法と、また一歩進んでバインディングを制御するアノテーションについて解説します。

XMLからJavaオブジェクトへの変換

データ構造としては前回と同じものを使いましょう。

会社(従業員*)
従業員(名前,給料)

これらを表すJavaクラスも前回と基本は同じなのですが、オブジェクトの中身を見たいのでtoString()を追加しています。

Campanyクラス

public class Company {
	private List<Employee> employees;

	public List<Employee> getEmployees() {
		return employees;
	}

	public void setEmployees(List<Employee> employees) {
		this.employees = employees;
	}

	@Override
	public String toString() {
		String str = "Company [n";
		if (employees != null) {
			for (Employee e : employees) {
				str += " " + e + "n";
			}
		}
		str += "]";
		return str;
	}
}

Employeeクラス

public class Employee {
	private String name;
	private int salary;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}

	@Override
	public String toString() {
		return "Employee [name=" + name + ", salary=" + salary + "]";
	}
}

では、XMLをこのクラスのオブジェクトに変換するプログラムがどうなるか見てみましょう。実際的にはXMLをファイルから読み込むなどすると思いますが、この例ではその場で文字列を作っています。

public class Sample2 {

	public static void main(String[] args) {
		String xml = "<?xml version="1.0" encoding="UTF-8" standalone="yes"?>"
				+ "<company>"
				+ "    <employees>"
				+ "        <name>taro</name>"
				+ "        <salary>1000</salary>"
				+ "    </employees>"
				+ "    <employees>"
				+ "        <name>hanako</name>"
				+ "        <salary>800</salary>"
				+ "    </employees>"
				+ "</company>";

		// アンマーシャル
		Company c = JAXB.unmarshal(new StringReader(xml), Company.class);

		System.out.println(c);
	}
}

これも前回同様ごく簡単ですね。JAXB#unmarshall()を呼ぶだけです。

実行すると以下の出力が得られます。

Company [
 Employee [name=taro, salary=1000]
 Employee [name=hanako, salary=800]
]

これで無事にXMLからJavaオブジェクトへ変換できました。

バインディングを制御する

さてこのように特に設定をしなくても、自動的にJavaオブジェクトとXMLとが(正確にはJavaクラスとXML Schemaとが)対応付けられて相互に変換できるわけですが、このままでは都合が悪いこともあります。

前回も触れたように、XML上、従業員の要素名が「employees」になっています。これはなぜかと言うとCompanyクラスのプロパティ名が「employees」だからです。もちろんプロパティ名を「employee」に変えれば要素名も変わるのですが、いつも都合良くプログラムを変えたり、XMLを変えたりできるとは限りません。

そこで登場するのがアノテーションです。Companyクラスを以下のようにしてみましょう。

public class Company {
	private List<Employee> employees;

	@XmlElementWrapper
	@XmlElement(name="employee")
	public List<Employee> getEmployees() {
		return employees;
	}

	public void setEmployees(List<Employee> employees) {
		this.employees = employees;
	}

	@Override
	public String toString() {
		String str = "Company [n";
		if (employees != null) {
			for (Employee e : employees) {
				str += " " + e + "n";
			}
		}
		str += "]";
		return str;
	}
}

名前からだいたい想像がつくかもしれませんね。このクラスを使ってJavaオブジェクトからXMLへの変換(前回のSample1)を行ってみると、以下のような出力が得られます。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
    <employees>
        <employee>
            <name>taro</name>
            <salary>1000</salary>
        </employee>
        <employee>
            <name>hanako</name>
            <salary>800</salary>
        </employee>
    </employees>
</company>

つまりそれぞれのアノテーションは以下のような働きをします。

@XmlElementWrapper
(主にコレクション要素の)外側をラップするXML要素を生成します。
@XmlElement
JavaBeanプロパティをXML要素としてマークします。nameプロパティでXML要素名を指定できます。

Employeeクラスの方も少し変えてみましょう。せっかくXMLなのですから属性を使いたいときもあるでしょう。

public class Employee {
	private String name;
	private int salary;

	@XmlAttribute
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@XmlAttribute
	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}

	@Override
	public String toString() {
		return "Employee [name=" + name + ", salary=" + salary + "]";
	}
}

これで再び変換を実行すると、出力は以下のように変わります。

<company>
    <employees>
        <employee salary="1000" name="taro"/>
        <employee salary="800" name="hanako"/>
    </employees>
</company>
@XmlAttribute
JavaBeanプロパティをXML属性としてマークします。

次回へ

ここまでで、JavaオブジェクトとXMLとの間をかなり自由に行き来できるようになりました。

次回は先延ばしにしていたXML Schemaが登場する予定です。JAXBのコマンド(CLI)を使ってJavaクラスとXML Schemaの変換を行います。

コメントを残す