JAXBガイド

** 1前書き

**

これはJAXB(XMLバインディングのためのJavaアーキテクチャー)の紹介記事です。

最初に、JavaオブジェクトからXMLへの変換、およびその逆の変換方法を説明します。次に、JAXB-2 Mavenプラグインを使用して、XMLスキーマからのJavaクラスの生成およびその逆の変換に焦点を当てます。

2概要

JAXBは、JavaオブジェクトをXMLに整列化(書き込み)し、XMLをオブジェクトに非整列化(読み取り)するための高速で便利な方法を提供します。 Javaアノテーションを使用してXML要素と属性をJavaフィールドとプロパティにマッピングするバインディングフレームワークをサポートします。

JAXB-2 Mavenプラグインは、その作業の大部分をJDK提供の2つのツールhttp://docs.oracle.com/javase/7/docs/technotes/tools/share/xjc.html[XJC]およびhttpのいずれかに委任しています。//docs.oracle.com/javase/7/docs/technotes/tools/share/schemagen.html[Schemagen]

3 JAXBアノテーション

JAXBは、生成されたクラスを追加情報で補強するためにJavaアノテーションを使用します。このようなアノテーションを既存のJavaクラスに追加すると、それらをJAXBランタイム用に準備できます。

マーシャリングとアンマーシャリングを説明する簡単なJavaオブジェクトを最初に作成しましょう。

@XmlRootElement(name = "book")
@XmlType(propOrder = { "id", "name", "date" })
public class Book {
    private Long id;
    private String name;
    private String author;
    private Date date;

    @XmlAttribute
    public void setId(Long id) {
        this.id = id;
    }

    @XmlElement(name = "title")
    public void setName(String name) {
        this.name = name;
    }

    @XmlTransient
    public void setAuthor(String author) {
        this.author = author;
    }

   //constructor, getters and setters
}

上記のクラスには以下の注釈が含まれています。

  • ルートXML要素の名前はクラス名から派生しています。

その名前を使用してXMLのルート要素の名前を指定することもできます。 属性 @ XmlType ** :フィールドがフィールドに書き込まれる順序を定義します。

XMLファイル @ XmlElement ** :使用される実際のXML要素名を定義する

  • idフィールドが要素ではなく属性としてマッピングされるように定義する

  • XMLに含めたくないフィールドに注釈を付ける

JAXBアノテーションの詳細については、次のhttp://docs.oracle.com/javaee/7/api/javax/xml/bind/annotation/package-summary.html[link]を参照してください。

4. マーシャリング

マーシャリングは、クライアントアプリケーションにJAXB派生のJavaオブジェクトツリーをXMLデータに変換する機能を提供します。デフォルトでは、 Marshaller はXMLデータの生成時にUTF-8エンコードを使用します。次に、JavaオブジェクトからXMLファイルを生成します。

JAXBバインディングフレームワーク操作の実装に必要なXML/Javaバインディング情報を管理するための抽象化を提供する JAXBContext を使用して簡単なプログラムを作成しましょう。

public void marshal() throws JAXBException, IOException {
    Book book = new Book();
    book.setId(1L);
    book.setName("Book1");
    book.setAuthor("Author1");
    book.setDate(new Date());

    JAXBContext context = JAXBContext.newInstance(Book.class);
    Marshaller mar= context.createMarshaller();
    mar.setProperty(Marshaller.JAXB__FORMATTED__OUTPUT, Boolean.TRUE);
    mar.marshal(book, new File("./book.xml"));
}

javax.xml.bind.JAXBContext クラスは、クライアントのJAXB APIへのエントリポイントを提供します。デフォルトでは、JAXBはXML文書をフォーマットしません。これによりスペースが節約され、空白が誤って重要と解釈されるのを防ぐことができます。

JAXBで出力をフォーマットするには、 Marshallerの Marshaller.JAXB FORMATTED OUTPUT プロパティを true__に設定するだけです。マーシャルメソッドは、オブジェクトと出力ファイルを使用して、生成されたXMLをパラメータとして格納します。

上記のコードを実行すると、 book.xml の結果を調べて、JavaオブジェクトをXMLデータに正常に変換したことを確認できます。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book id="1">
    <title>Book1</title>
    <date>2016-11-12T11:25:12.227+07:00</date>
</book>

5非整列化

非整列化は、クライアントアプリケーションにXMLデータをJAXB派生Javaオブジェクトに変換する機能を提供します。

JAXBの Unmarshaller を使用して、__book.xmlを非整列化してJavaオブジェクトに戻します。

public Book unmarshall() throws JAXBException, IOException {
    JAXBContext context = JAXBContext.newInstance(Book.class);
    return (Book) context.createUnmarshaller()
      .unmarshal(new FileReader("./book.xml"));
}

上記のコードを実行すると、コンソール出力を調べて、XMLデータをJavaオブジェクトに正常に変換したことを確認できます。

Book[id=1, name=Book1, author=null, date=Sat Nov 12 11:38:18 ICT 2016]----

===  **  6. ** 複雑なデータ型

JAXBでは直接利用できない可能性がある複雑なデータ型を処理する場合、JAXBに特定の型の管理方法を指示するためのアダプタを作成することがあります。

JAXBの__XmlAdapter__を使用して、マッピング不可能なクラスをJAXBが処理できるものに変換するためのカスタムコードを定義できます。 __ @ XmlJavaTypeAdapter__アノテーションは、カスタムマーシャリング用に__XmlAdapter__クラスを拡張するアダプタを使用します。

マーシャリング時に日付形式を指定するためのアダプタを作成しましょう。

[source,java,gutter:,true]

public class DateAdapter extends XmlAdapter<String, Date> {

private static final ThreadLocal<DateFormat> dateFormat
  = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};
@Override
public Date unmarshal(String v) throws Exception {
    return dateFormat.get().parse(v);
}
    @Override
    public String marshal(Date v) throws Exception {
        return dateFormat.get().format(v);
    }
}
整列化するときに__Date__を__String__に変換するには日付形式「__yyyy-MM-dd HH:mm:ss__」を使用し、__DateFormat__をスレッドセーフにするには__ThreadLocal__を使用します。

__DateAdapter__を__Book__に適用しましょう。

[source,java,gutter:,true]

@XmlRootElement(name = "book") @XmlType(propOrder = { "id", "name", "date" }) public class Book { private Long id; private String name; private String author; private Date date;

@XmlAttribute
public void setId(Long id) {
    this.id = id;
}
@XmlTransient
public void setAuthor(String author) {
    this.author = author;
}
@XmlElement(name = "title")
public void setName(String name) {
    this.name = name;
}
    @XmlJavaTypeAdapter(DateAdapter.class)
    public void setDate(Date date) {
        this.date = date;
    }
}
上記のコードを実行すると、__book.xml__の結果を確認して、新しい日付形式 "__yyyy-MM-dd HH:mm:ss__"を使用してJavaオブジェクトをXMLに正常に変換したことを確認できます。

[source,xml,gutter:,true]

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <book id="1"> <title>Book1</title> <date>2016-11-10 23:44:18</date>final </book>

===  **  7.  JAXB-2 Mavenプラグイン+

**

このプラグインはXMLバインディング用Java API(JAXB)バージョン2を使用して、XMLスキーマ(およびオプションでバインディングファイル)からJavaクラスを生成したり、注釈付きのJavaクラスからXMLスキーマを作成したりします。

Webサービスを構築するための2つの基本的なアプローチ、__最後の契約__と__最初の契約__があることに注意してください。これらのアプローチの詳細については、以下のhttp://docs.spring.io/spring-ws/site/reference/html/why-contract-first.html[link]をチェックしてください。

====  **  7.1.  XSD ** からJavaクラスを生成する

JAXB-2 Mavenプラグインは、JDK提供のツールXJC、XSD(XML Schema Definition)からJavaクラスを生成するJAXBバインディングコンパイラツールを使用します。

単純な__user.xsd__ファイルを作成し、JAXB-2 Mavenプラグインを使用してこのXSDスキーマからJavaクラスを生成しましょう。

[source,xml,gutter:,true]

<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="/jaxb/gen" xmlns:userns="/jaxb/gen" elementFormDefault="qualified">

<element name="userRequest" type="userns:UserRequest"></element>
<element name="userResponse" type="userns:UserResponse"></element>
<complexType name="UserRequest">
    <sequence>
        <element name="id" type="int"/>
        <element name="name" type="string"/>
    </sequence>
</complexType>
    <complexType name="UserResponse">
        <sequence>
            <element name="id" type="int"/>
            <element name="name" type="string"/>
            <element name="gender" type="string"/>
            <element name="created" type="dateTime"/>
        </sequence>
    </complexType>
</schema>
JAXB-2 Mavenプラグインを設定しましょう。

[source,xml,gutter:,true]

<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>2.3</version> <executions> <execution> <id>xjc</id> <goals> <goal>xjc</goal> </goals> </execution> </executions> <configuration> <xjbSources> <xjbSource>src/main/resources/global.xjb</xjbSource> </xjbSources> <sources> <source>src/main/resources/user.xsd</source> </sources> <outputDirectory>${basedir}/src/main/java</outputDirectory> <clearOutputDir>false</clearOutputDir> </configuration> </plugin>

デフォルトでは、このプラグインは__src/main/xsd__にあるXSDファイルを見つけます。それに応じて__pom.xml__のこのプラグインの設定セクションを変更することでXSD検索を設定することができます。

デフォルトでは、これらのJavaクラスは__target/generated-resources/jaxb__フォルダーに生成されます。プラグイン設定に__outputDirectory__要素を追加することで出力ディレクトリを変更することができます。このディレクトリ内のファイルが消去されないように、falseの値を持つ__clearOutputDir__要素を追加することもできます。

デフォルトのバインディング規則をオーバーライドするグローバルJAXBバインディングを設定することもできます。

[source,xml,gutter:,true]

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema" jaxb:extensionBindingPrefixes="xjc">

    <jaxb:globalBindings>
        <xjc:simple/>
        <xjc:serializable uid="-1"/>
        <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
            parse="javax.xml.bind.DatatypeConverter.parseDateTime"
            print="javax.xml.bind.DatatypeConverter.printDateTime"/>
    </jaxb:globalBindings>
</jaxb:bindings>
上記の__global.xjb__は、__dateTime__タイプを__java.util.Calendar__タイプにオーバーライドします。 +プロジェクトをビルドすると、__src/main/java__フォルダーとパッケージ__com.baeldung.jaxb.gen__にクラスファイルが生成されます。

====  **  7.2.  Java ** からXSDスキーマを生成する

同じプラグインがJDK提供のツール__Schemagen__を使用しています。これは、JavaクラスからXSDスキーマを生成できるJAXBバインディングコンパイラツールです。

JavaクラスがXSDスキーマ候補に適格となるためには、クラスに__ @ XmlType__アノテーションを付けなければなりません。

前の例のJavaクラスファイルを再利用します。プラグインを設定しましょう。

[source,xml,gutter:,true]

<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>2.3</version> <executions> <execution> <id>schemagen</id> <goals> <goal>schemagen</goal> </goals> </execution> </executions> <configuration> <sources> <source>src/main/java/com/baeldung/jaxb/gen</source> </sources> <outputDirectory>src/main/resources</outputDirectory> <clearOutputDir>false</clearOutputDir> <transformSchemas> <transformSchema> <uri>/jaxb/gen</uri> <toPrefix>user</toPrefix> <toFile>user-gen.xsd</toFile> </transformSchema> </transformSchemas> </configuration> </plugin>

デフォルトでは、JAXBは注釈付きのJAXBクラスについて、__src/main/java__の下のすべてのフォルダを再帰的にスキャンします。プラグイン構成に__source__要素を追加することで、JAXBアノテーション付きクラスに別の__source__フォルダーを指定できます。

XSDスキーマの命名を担当するポストプロセッサ__transformSchemas__を登録することもできます。これは、__namespace__をJavaクラスの__ @ XmlType__の名前空間と照合することによって機能します。

プロジェクトをビルドすると、__src/main/resources__ディレクトリに__user-gen.xsd__ファイルが生成されます。

===  **  8. **  ** 結論**

この記事では、JAXBの概要について説明しました。詳細については、http://www.oracle.com/technetwork/articles/javase/index-140168.html[JAXB home page]を参照してください。

この記事のソースコードはhttps://github.com/eugenp/tutorials/tree/master/jaxb[GitHub]にあります。