JAXBを使ってxmlファイルを出力する[Java]

JAXBってなに

Java Achitecture for XML Bindingの略.
XMLJava Objectを相互変換するためのAPIのことです.

イメージ図としてはこんな感じ.
f:id:xrdnk:20200108204932p:plain

Marshalとは「整列化する」といった意味です.
JavaオブジェクトをXML文字列へ整列化します.
Unmarshalはその逆で「非整列化する」という意味で,
XMLの文字列として整列化されたものをJavaオブジェクトに戻します.

主要インタフェース

インタフェース名 説明
JAXBContext JAXB APIへのエントリポイントの提供
Marshaller JavaオブジェクトをXMLデータに変換
Unmarshaller XMLデータをJavaオブジェクトに変換

今回はMarshal処理を行いたいので,Unmarshallerの説明を割愛します.

JAXBContextインタフェース

        // JAXBContextインスタンスの生成
        JAXBContext context = null;
        try {
            context = JAXBContext.newInstance("com.acme.foo" );
        } catch (JAXBException e) {
            throw e;
        }

newInstanceメソッドを利用して,JAXBContextの新しいインスタンスを取得します.
newInstanceメソッドの引数はコンテキストパスやクラスを指定したりします.

JAXBContext (Java Platform SE 6)

Marshallerインタフェース

        // JAXBContextインスタンスの生成
        JAXBContext context = null;
        try {
            context = JAXBContext.newInstance("com.acme.foo" );
        } catch (JAXBException e) {
            throw e;
        }
        // Marshallerインスタンスの生成
        Marshaller marshaller = context.createMarshaller();
        // Marshallerのプロパティを設定
        // XML出力エンコーディングの指定
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        // XMLデータを改行とインデントを使用して書式設定するか否か
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));

        // Javaオブジェクト→XML変換処理
        try (OutputStream os = new FileOutputStream("item.xml")) {
            // Javaオブジェクト→XML
            marshaller.marshal(obj, outputStream);
        } catch (JAXBException | IOException e) {
            throw e;
       }

Marshallerインスタンス生成とプロパティ設定

JAXBContextのcreateMarshallerメソッドを使用して,
MarShallerインスタンスを生成します. XMLデータにプロパティを設定することができます.
このサンプルプログラムではUTF-8出力と改行・インデントの指定の設定をしています.

プロパティ名 説明
JAXB_ENCODING 整列化されたXMLデータの出力エンコーディングを指定する
JAXB_FORMATTED_OUTPUT 整列化されたXMLデータを改行とインデントを使用して書式設定するかどうかを指定する

他にもプロパティが存在します.詳細は以下のサイトを参考に.
Marshaller (Java Platform SE 6)

Marshal処理

marshalメソッドでJava ObjectからXMLに変換します.
第1引数には変換元のJava Objectを指定して,第2引数にはXML変換後の出力先を指定します.

marshalメソッド内ではクローズを行わないため,自分でクローズする必要があります.
ここではtry-with-resourcesを使ってます.

実際に自分で作ってみた

JAXBTestProgramクラス

Java Object を XMLデータに出力する動作確認クラスです.

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

/**
 * Java Object を XMLデータに出力する動作確認クラス
 */
public class JAXBTestProgram {

    public static void main(String[] args) throws Exception {

        // 出力ファイル名の指定
        String fileName = "C:/tmp/test.xml";

        // テスト用Java Objectのリストを生成
        List<JavaTestBean> list = new ArrayList<>();
        list.add(new JavaTestBean(1, "aaa"));
        list.add(new JavaTestBean(2, "bbb"));
        list.add(new JavaTestBean(3, "ccc"));

        // Java Objectのリストの保持
        ExampleBean exampleBean = new ExampleBean();
        exampleBean.setBeanList(list);

        JAXBContext context = null;
        try {
            // JAXBContextインスタンス生成
            context = JAXBContext.newInstance(exampleBean.getClass());
        } catch (JAXBException e) {
            throw e;
        }

        Marshaller marshaller = null;
        try (OutputStream os = new FileOutputStream(fileName)) {
            // Marshallerインスタンス生成
            marshaller = context.createMarshaller();
            // XMLデータのプロパティ設定
            // エンコーディングの設定
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            // 改行・インデント指定の設定
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            // Marshal処理
            marshaller.marshal(exampleBean, os);
            // 出力したのをログで知らせる
            System.out.println("xml出来たよ(^^)");
        } catch (JAXBException | IOException e) {
            throw e;
        }
    }
}

JavaTestBeanクラス

サンプルJava Objectクラスです.

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * サンプルJava Objectクラス
 */
@XmlRootElement(name = "root")
public class JavaTestBean {

    /** id */
    private int id;

    /** name */
    private String name;

    public JavaTestBean() {}

    public JavaTestBean(int id, String name) {
        setId(id);
        setName(name);
    }

    @XmlElement
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

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

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

ExampleBeanクラス

サンプルJava Objectクラスのリストを保持するクラスです.
つまりこれはJavaTestBeanの上の階層になります.

package jaxbtest;

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * サンプルJava Objectクラスのリストを保持するクラス
 */
@XmlRootElement(name = "root")
public class ExampleBean {

    /** 保持するリスト */
    private List<JavaTestBean> beanList;

    @XmlElement(name = "record")
    public List<JavaTestBean> getBeanList() {
        return beanList;
    }

    public void setBeanList(List<JavaTestBean> beanList) {
        this.beanList = beanList;
    }
}

アノテーションを使って調整しています.
XMLデータのルート要素名を@XmlRootElementで指定します.
@XmlElementをGetterかSetterメソッドにつけてタグ名を指定します.
属性名を指定したい場合は@XmlAttributeを使います.

出力結果

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <record>
        <id>1</id>
        <name>aaa</name>
    </record>
    <record>
        <id>2</id>
        <name>bbb</name>
    </record>
    <record>
        <id>3</id>
        <name>ccc</name>
    </record>
</root>

アノテーションを駆使すれば求めている出力形式のxmlデータが出せそう.

終わりに

Eclipseだとコメントアウトの所でMarshallerって書くとスペルミスだよの~波線って出る.
Marshalerって書いたら波線がなくなったけど,MarshalerでもMarshallerでも同じ意味.
APIではMarshallerって書いてあるから,別にスペルミスの~波線出なくていいよ頼むよEclipse
Eclipse重すぎてIntelliJが恋しい.やっぱりJetBrainsで快適プヨヨグラミングがしたいなあ~.
学生の頃は無料サブスクリプションで使い放題だったけど,社会人だとお金かかるのが世知辛い.

参考記事

Java Architecture for XML Binding - Wikipedia
XMLDBとJavaAPI、JAXB2.0を活用したWebアプリケーション開発(APIチュートリアル編) (1/3):CodeZine(コードジン)
JAXB (Java Platform SE 6)
Java XML JAXBメモ(Hishidama's XML JAXB Memo)
JAXB使い方メモ - Qiita