Membatalkan Pengaturan Tanggal Menggunakan JAXB

1. Perkenalan

Dalam tutorial ini, kita akan melihat bagaimana mengurai objek tanggal dengan format berbeda menggunakan JAXB.

Pertama, kita akan membahas format tanggal skema default. Kemudian, kita akan mempelajari cara menggunakan format yang berbeda. Kami juga akan melihat bagaimana kami dapat menangani tantangan umum yang muncul dengan teknik ini.

2. Skema ke Java Binding

Pertama, kita perlu memahami hubungan antara tipe data XML Schema dan Java . Secara khusus, kami tertarik pada pemetaan antara XML Schema dan objek tanggal Java.

Menurut pemetaan Schema to Java , ada tiga tipe data Schema yang perlu kita pertimbangkan: xsd: date , xsd: time dan xsd: dateTime . Seperti yang bisa kita lihat, semuanya dipetakan ke javax.xml.datatype.XMLGregorianCalendar .

Kami juga perlu memahami format default untuk jenis Skema XML ini. Tipe data xsd: date dan xsd: time memiliki formatYYYY-MM-DD” dan “ hh: mm: ss” . Format xsd: dateTime adalah “ YYYY-MM-DDThh: mm: ss” di mana “ T” adalah pemisah yang menunjukkan awal bagian waktu.

3. Menggunakan Format Tanggal Skema Default

Kita akan membuat contoh objek tanggal unmarshals. Mari kita fokus pada tipe data xsd: dateTime karena ini adalah superset dari tipe lainnya.

Mari gunakan file XML sederhana yang mendeskripsikan buku:

 Book1 1979-10-21T03:31:12 

Kami ingin memetakan file ke objek Buku Java yang sesuai :

@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() + "]"; } }

Terakhir, kita perlu membuat aplikasi klien yang mengubah data XML menjadi objek Java turunan JAXB:

public static Book unmarshalDates(InputStream inputFile) throws JAXBException { JAXBContext jaxbContext = JAXBContext.newInstance(Book.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); return (Book) jaxbUnmarshaller.unmarshal(inputFile); }

Dalam kode di atas, kami telah mendefinisikan JAXBContext yang merupakan titik masuk ke JAXB API. Kemudian, kami telah menggunakan JAXB Unmarshaller pada aliran input untuk membaca objek kami:

Jika kita menjalankan kode di atas dan mencetak hasilnya, kita akan mendapatkan objek Book berikut :

[title: Book1; published: 1979-11-28T02:31:32]

Kita harus mencatat bahwa, meskipun pemetaan default untuk xsd: dateTime adalah XMLGregorianCalendar , kita juga dapat menggunakan jenis Java yang lebih umum: java.util.Date dan java.util.Calendar , menurut panduan pengguna JAXB.

4. Menggunakan Format Tanggal Kustom

Contoh di atas berfungsi karena kami menggunakan format tanggal skema default, "YYYY-MM-DDThh: mm: ss".

Namun bagaimana jika kita ingin menggunakan format lain seperti "TTTT-BB-HH jj: mm: dd", menghapus pembatas "T" ? Jika kita mengganti pembatas dengan karakter spasi di file XML kita, penguraian default akan gagal.

4.1. Membangun XmlAdapter Kustom

Untuk menggunakan format tanggal yang berbeda, kita perlu mendefinisikan XmlAdapter .

Mari kita lihat juga cara memetakan tipe xsd: dateTime ke objek java.util.Date dengan XmlAdapter khusus kami :

public class DateAdapter extends XmlAdapter { 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); } }

Di adaptor ini, kami telah menggunakan SimpleDateFormat untuk memformat tanggal kami. Kita harus hati-hati karena yang SimpleDateFormat tidak thread-safe. Untuk menghindari beberapa utas mengalami masalah dengan objek SimpleDateFormat bersama , kami membuat utas baru setiap kali kami membutuhkannya.

4.2. The XmlAdapter Internal 's

Seperti yang bisa kita lihat, XmlAdapter memiliki dua parameter tipe , dalam hal ini, String dan Tanggal . Yang pertama adalah tipe yang digunakan di dalam XML dan disebut tipe nilai. Dalam hal ini, JAXB tahu cara mengubah nilai XML menjadi String . Yang kedua disebut tipe terikat dan berhubungan dengan nilai dalam objek Java kita.

Tujuan adaptor adalah untuk mengonversi antara tipe nilai dan tipe terikat, dengan cara yang tidak dapat dilakukan JAXB secara default.

Untuk membuat Adaptor Xml kustom , kita harus mengganti dua metode: XmlAdapter.marshal () dan XmlAdapter.unmarshal () .

Selama unmarshalling, kerangka kerja pengikatan JAXB pertama-tama mengurai representasi XML ke String , lalu memanggil DateAdapter.unmarshal () untuk menyesuaikan tipe nilai ke Tanggal . Selama marshalling, kerangka kerja pengikatan JAXB memanggil DateAdapter.marshal () untuk mengadaptasi Tanggal ke String , yang kemudian disusun ke representasi XML.

4.3. Mengintegrasikan melalui Anotasi JAXB

The DateAdapter bekerja seperti plugin untuk JAXB dan kita akan pasang ke lapangan tanggal kami menggunakan @XmlJavaTypeAdapter penjelasan. The @XmlJavaTypeAdapte r penjelasan menentukan penggunaan XmlAdapter untuk unmarshalling kustom :

@XmlRootElement(name = "book") public class BookDateAdapter { // same as before @XmlElement(name = "published", required = true) @XmlJavaTypeAdapter(DateAdapter.class) private Date published; // same as before }

Kami juga menggunakan anotasi JAXB standar: anotasi @XmlRootElement dan @XmlElement .

Terakhir, mari kita jalankan kode baru:

[title: Book1; published: Wed Nov 28 02:31:32 EET 1979]

5. Tanggal Pembongkaran di Jawa 8

Java 8 memperkenalkan API Tanggal / Waktu baru . Di sini, kita akan fokus pada kelas LocalDateTime yang merupakan salah satu yang paling umum digunakan.

5.1. Membangun XmlAdapter berbasis LocalDateTime

By default, JAXB cannot automatically bind an xsd:dateTime value to a LocalDateTime object regardless of the date format. In order to convert an XML Schema date value to or from a LocalDateTime object, we need to define another XmlAdapter similar to the previous one:

public class LocalDateTimeAdapter extends XmlAdapter { 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); } }

In this case, we've used a DateTimeFormatter instead of a SimpleDateFormat. The former was introduced in Java 8 and it's compatible with the new Date/Time API.

Note that the conversion operations can share a DateTimeFormatter object because the DateTimeFormatter is thread-safe.

5.2. Integrating the New Adapter

Now, let's replace the old adapter with the new one in our Book class and also Date with LocalDateTime:

@XmlRootElement(name = "book") public class BookLocalDateTimeAdapter { // same as before @XmlElement(name = "published", required = true) @XmlJavaTypeAdapter(LocalDateTimeAdapter.class) private LocalDateTime published; // same as before }

If we run the above code, we'll get the output:

[title: Book1; published: 1979-11-28T02:31:32]

Note that the LocalDateTime.toString() adds the “T” delimiter between date and time.

6. Conclusion

In this tutorial, we explored unmarshalling dates using JAXB.

First, we looked at the XML Schema to Java data type mapping and created an example using the default XML Schema date format.

Next, we learned how to use a custom date format based on a custom XmlAdapter and saw how to handle the thread safety of SimpleDateFormat.

Terakhir, kami memanfaatkan API Tanggal / Waktu Java 8 yang superior, aman untuk thread, dan tanggal yang tidak diatur dengan format kustom.

Seperti biasa, kode sumber yang digunakan dalam tutorial tersedia di GitHub.