JAXBを使用した日付の非整列化

1. 前書き

このチュートリアルでは、*異なる形式の日付オブジェクトを非整列化する方法を確認しますlink:/jaxb[using JAXB]。*
最初に、デフォルトのスキーマ日付形式について説明します。 次に、さまざまな形式の使用方法について説明します。 また、これらの手法で発生する一般的な課題にどのように対処できるかについても説明します。

2. スキーマからJavaへのバインディング

まず、* XMLスキーマとJavaデータ型の関係を理解する必要があります*。 特に、XMLスキーマとJava日付オブジェクト間のマッピングに関心があります。
  • https://docs.oracle.com/javase/tutorial/jaxb/intro/bind.html [スキーマからJavaへのマッピング] によると、考慮する必要がある3つのスキーマデータタイプがあります。 xsd: date _、 xsd:time_、および_xsd:dateTime_ 。 ご覧のとおり、これらはすべて javax.xml.datatype.XMLGregorianCalendar *にマッピングされています。

    *これらのXMLスキーマタイプのhttps://www.w3schools.com/xml/schema_dtypes_date.asp [デフォルト形式]も理解する必要があります。* _xsd:date_および_xsd:time_データタイプには「_YYYY-MM-DD ” _および“ _hh:mm:ss” _形式。 * _xsd:dateTime_形式は「_YYYY-MM-DDThh:mm:ss」_ *です。「_ T」_は時間セクションの開始を示す区切り文字です。

3. デフォルトのスキーマ日付形式の使用

日付オブジェクトを非整列化する例を作成します。 _xsd:dateTime_データ型に注目しましょう。これは、他の型のスーパーセットであるためです。
本を記述する簡単なXMLファイルを使用してみましょう。
<book>
    <title>Book1</title>
    <published>1979-10-21T03:31:12</published>
</book>
ファイルを対応するJava _Book_オブジェクトにマップします。
@XmlRootElement(name = "book")
public class Book {

    @XmlElement(name = "title", required = true)
    private String title;

    @XmlElement(name = "published", required = true)
    private XMLGregorianCalendar published;

    @Override
    public String toString() {
        return "[title: " + title + "; published: " + published.toString() + "]";
    }

}
最後に、XMLデータをJAXBから派生したJavaオブジェクトに変換するクライアントアプリケーションを作成する必要があります。
public static Book unmarshalDates(InputStream inputFile)
  throws JAXBException {
    JAXBContext jaxbContext = JAXBContext.newInstance(Book.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    return (Book) jaxbUnmarshaller.unmarshal(inputFile);
}
上記のコードでは、JAXB APIへのエントリポイントである_JAXBContext_を定義しています。 次に、オブジェクトを読み取るために、入力ストリームでJAXB _Unmarshaller_を使用しました。
上記のコードを実行して結果を出力すると、次の_Book_オブジェクトが取得されます。
[title: Book1; published: 1979-11-28T02:31:32]
_xsd:dateTime_のデフォルトのマッピングは_XMLGregorianCalendar_ですが、https:// javaeeによれば、より一般的なJavaタイプ_java.util.Date_および_java.util.Calendar、_を使用することもできます。 .github.io / jaxb-v2 / doc / user-guide / ch03.html#customization-of-schema-compilation-using-different-datatypes [JAXBユーザーガイド]。

4. カスタム日付形式の使用

上記の例は、デフォルトのスキーマ日付形式_“ YYYY-MM-DDThh:mm:ss” ._を使用しているため機能します
しかし、_“ YYYY-MM-DD hh:mm:ss”、_のような別のフォーマットを使用したい場合は、_“ T” _区切り文字を削除しますか? XMLファイルで区切り文字をスペース文字に置き換えると、デフォルトのアンマーシャリングは失敗します。

4.1. カスタム_XmlAdapter_の構築

*異なる日付形式を使用するには、_XmlAdapter_を定義する必要があります。*
カスタム_XmlAdapter:_を使用して、_xsd:dateTime_型を_java.util.Date_オブジェクトにマップする方法も見てみましょう。
public class DateAdapter extends XmlAdapter<String, Date> {

    private static final String CUSTOM_FORMAT_STRING = "yyyy-MM-dd HH:mm:ss";

    @Override
    public String marshal(Date v) {
        return new SimpleDateFormat(CUSTOM_FORMAT_STRING).format(v);
    }

    @Override
    public Date unmarshal(String v) throws ParseException {
        return new SimpleDateFormat(CUSTOM_FORMAT_STRING).parse(v);
    }

}
このアダプターでは、* https://www.baeldung.com/java-simple-date-format [_SimpleDateFormat_]を使用して日付をフォーマットしました。* _SimpleDateFormat_はhttpsではないので注意する必要があります。 //www.baeldung.com/java-thread-safety[thread-safe].*共有_SimpleDateFormat_オブジェクトで複数のスレッドで問題が発生するのを防ぐため、必要なたびに新しいスレッドを作成しています。

4.2. XmlAdapter ’の内部

ご覧のとおり、* _ XmlAdapter_には2つの型パラメーター*があり、この場合は_String_と_Date_です。 最初のものは、XML内で使用されるタイプであり、値タイプと呼ばれます。 この場合、JAXBはXML値を_String_に変換する方法を知っています。 2番目はバインド型と呼ばれ、Javaオブジェクトの値に関連しています。
*アダプタの目的は、JAXBがデフォルトで実行できない方法で、値型とバインド型の間で変換することです。*
カスタム_XmlAdapter_を構築するには、2つのメソッド_XmlAdapter.marshal()_および_XmlAdapter.unmarshal()_をオーバーライドする必要があります。
マーシャリング解除中、JAXBバインディングフレームワークは最初にXML表現を_String_にアンマーシャリングし、次に_DateAdapter.unmarshal()_を呼び出して、値型を_Date_に適合させます。 マーシャリング中、JAXBバインディングフレームワークは_DateAdapter.marshal()_を呼び出して_Date_を_String_に適合させ、XML表現にマーシャリングします。

4.3. JAXBアノテーションを介した統合

_DateAdapter_はJAXBのプラグインのように機能し、_ @ XmlJavaTypeAdapter_アノテーションを使用して日付フィールドに添付します。 * __ @ XmlJavaTypeAdapte__rアノテーションは、カスタムアンマーシャリングに_XmlAdapter_の使用を指定します*:
@XmlRootElement(name = "book")
public class BookDateAdapter {

    // same as before

    @XmlElement(name = "published", required = true)
    @XmlJavaTypeAdapter(DateAdapter.class)
    private Date published;

    // same as before

}
また、https://www.baeldung.com/jaxb [標準JAXBアノテーション]:_ @ XmlRootElement_および_ @ XmlElement_アノテーションも使用しています。
最後に、新しいコードを実行しましょう。
[title: Book1; published: Wed Nov 28 02:31:32 EET 1979]

5. Java 8での日付の非整列化

Java 8は、新しいlink:/java-8-date-time-intro[_Date/Time_ API]を導入しました。 ここでは、最も一般的に使用される_LocalDateTime_クラスに焦点を当てます。

5.1. _ LocalDateTime ベース XmlAdapter _の構築

デフォルトでは、* JAXBは、日付形式に関係なく、_xsd:dateTime_値を_LocalDateTime_ *オブジェクトに自動的にバインドできません。 XMLスキーマの日付値を_LocalDateTime_オブジェクトとの間で変換するには、前と同様の別の_XmlAdapter_を定義する必要があります。
public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> {

    private DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public String marshal(LocalDateTime dateTime) {
        return dateTime.format(dateFormat);
    }

    @Override
    public LocalDateTime unmarshal(String dateTime) {
        return LocalDateTime.parse(dateTime, dateFormat);
    }

}
この場合、* SimpleDateFormat_。の代わりにlink:/java-datetimeformatter[_DateTimeFormatter_]を使用しました。*前者はJava 8で導入され、新しい_Date / Time_ APIと互換性があります。
  • _DateTimeFormatter_はスレッドセーフであるため、変換操作は_DateTimeFormatter_オブジェクトを共有できることに注意してください。

5.2. 新しいアダプターの統合

次に、_Book_ classの古いアダプターを新しいアダプターに置き換え、_Date_を_LocalDateTime_に置き換えます。
@XmlRootElement(name = "book")
public class BookLocalDateTimeAdapter {

    // same as before

    @XmlElement(name = "published", required = true)
    @XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
    private LocalDateTime published;

    // same as before

}
上記のコードを実行すると、出力が取得されます。
[title: Book1; published: 1979-11-28T02:31:32]
_LocalDateTime.toString()_は、日付と時刻の間に_“ T” _区切り文字を追加することに注意してください。

6. 結論

このチュートリアルでは、JAXBを使用した*日付の非整列化*を検討しました。
最初に、XMLスキーマからJavaデータ型へのマッピングを見て、デフォルトのXMLスキーマの日付形式を使用して例を作成しました。
次に、カスタム_XmlAdapter_に基づいてカスタム日付形式を使用する方法を学び、_SimpleDateFormat_のスレッドセーフを処理する方法を見ました。
最後に、優れた、スレッドセーフなJava 8 Date / Time APIと非整列化された日付をカスタム形式で活用しました。
いつものように、チュートリアルで使用されるソースコードはhttps://github.com/eugenp/tutorials/tree/master/jaxb[GitHubで]から入手できます。