Tarikh Tidak Mencabut Menggunakan JAXB

1. Pengenalan

Dalam tutorial ini, kita akan melihat cara membongkar objek tarikh dengan format yang berbeza menggunakan JAXB.

Pertama, kita akan merangkumi format tarikh skema lalai. Kemudian, kita akan meneroka cara menggunakan format yang berbeza. Kita juga akan melihat bagaimana kita dapat menangani cabaran bersama yang timbul dengan teknik ini.

2. Skema ke Java Binding

Pertama, kita perlu memahami hubungan antara Skema XML dan jenis data Java . Secara khusus, kami berminat untuk memetakan antara Skema XML dan objek tarikh Java.

Menurut pemetaan Skema ke Java , ada tiga jenis data Skema yang perlu kita pertimbangkan: xsd: date , xsd: time dan xsd: dateTime . Seperti yang dapat kita lihat, semuanya dipetakan ke javax.xml.datatype.XMLGregorianCalendar .

Kita juga perlu memahami format lalai untuk jenis Skema XML ini. Jenis data xsd: date dan xsd: time mempunyai format " YYYY-MM-DD" dan " hh: mm: ss" . The XSD: Masa tarikh format adalah " YYYY-MM-HHMjj: mm: ss" di mana " T" ialah pemisah yang menunjukkan permulaan seksyen masa.

3. Menggunakan Format Tarikh Skema Lalai

Kami akan membina contoh bahawa unmarhals tarikh objek. Mari fokus pada jenis data xsd: dateTime kerana ia adalah superset dari jenis lain.

Mari gunakan fail XML ringkas yang menerangkan buku:

 Book1 1979-10-21T03:31:12 

Kami ingin memetakan fail ke objek Java Book 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() + "]"; } }

Akhirnya, kita perlu membuat aplikasi klien yang menukar data XML ke objek Java yang berasal dari 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 kod di atas, kami telah menentukan konteks JAXBC yang merupakan titik masuk ke API JAXB. Kemudian, kami telah menggunakan JAXB Unmarshaller pada aliran input untuk membaca objek kami:

Sekiranya kita menjalankan kod di atas dan mencetak hasilnya, kita akan mendapat objek Buku berikut :

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

Kita harus perhatikan bahawa, walaupun pemetaan lalai untuk xsd: dateTime adalah XMLGregorianCalendar , kita juga boleh menggunakan jenis Java yang lebih umum: java.util.Date dan java.util.Calendar , menurut panduan pengguna JAXB.

4. Menggunakan Format Tarikh Tersuai

Contoh di atas berfungsi kerana kita menggunakan format tarikh skema lalai, "YYYY-MM-DDThh: mm: ss".

Tetapi bagaimana jika kita ingin menggunakan format lain seperti "YYYY-MM-DD hh: mm: ss", menyingkirkan pembatas "T" ? Sekiranya kita mengganti pembatas dengan watak spasi dalam fail XML kita, unmarshalling lalai akan gagal.

4.1. Membangun Adaptor Xml Custom

Untuk menggunakan format tarikh yang berbeza, kita perlu menentukan XmlAdapter .

Mari kita lihat juga bagaimana memetakan jenis xsd: dateTime ke objek java.util.Date dengan XmlAdapter tersuai 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); } }

Dalam penyesuai ini, kami telah menggunakan SimpleDateFormat untuk memformat tarikh kami. Kita perlu berhati-hati kerana yang SimpleDateFormat tidak benang-selamat. Untuk mengelakkan beberapa utas mengalami masalah dengan objek SimpleDateFormat yang dikongsi , kami membuat yang baru setiap kali memerlukannya.

4.2. The XmlAdapter 's Internals

Seperti yang kita lihat, XmlAdapter mempunyai dua jenis parameter , dalam kes ini, String dan Date . Yang pertama adalah jenis yang digunakan di dalam XML dan dipanggil jenis nilai. Dalam kes ini, JAXB tahu bagaimana menukar nilai XML menjadi String . Yang kedua disebut jenis terikat dan berkaitan dengan nilai dalam objek Java kita.

Objektif penyesuai adalah menukar antara jenis nilai dan jenis terikat, dengan cara yang tidak dapat dilakukan JAXB secara lalai.

Untuk membina Adaptor Xml khusus , kita harus mengganti dua kaedah: XmlAdapter.marshal () dan XmlAdapter.unmarshal () .

Semasa unmarshalling, kerangka pengikatan JAXB terlebih dahulu melepaskan representasi XML ke String dan kemudian memanggil DateAdapter.unmarshal () untuk menyesuaikan jenis nilai ke Date . Semasa marshalling, kerangka pengikatan JAXB memanggil DateAdapter.marshal () untuk menyesuaikan Date to String , yang kemudian disusun ke representasi XML.

4.3. Mengintegrasikan melalui Anotasi JAXB

The DateAdapter berfungsi seperti plugin untuk JAXB dan kita akan lampirkan ia ke medan tarikh kami menggunakan @XmlJavaTypeAdapter anotasi. The @XmlJavaTypeAdapte r anotasi menentukan penggunaan yang XmlAdapter untuk unmarshalling adat :

@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 standard: @XmlRootElement dan @XmlElement anotasi.

Akhirnya, mari kita jalankan kod baru:

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

5. Tarikh Tidak Menghantar di Java 8

Java 8 memperkenalkan API Tarikh / Masa baru . Di sini, kita akan memberi tumpuan kepada kelas LocalDateTime yang merupakan salah satu yang paling biasa digunakan.

5.1. Membangun Adaptor Xml berasaskan LocalDateTime

Secara lalai, JAXB tidak dapat mengikat nilai xsd: dateTime secara automatik ke objek LocalDateTime tanpa mengira format tarikh. Untuk menukar nilai tarikh Skema XML ke atau dari objek LocalDateTime , kita perlu menentukan XmlAdapter lain yang serupa dengan yang sebelumnya:

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); } }

Dalam kes ini, kami telah menggunakan DateTimeFormatter dan bukannya SimpleDateFormat . Yang pertama diperkenalkan di Java 8 dan serasi dengan API Tarikh / Masa yang baru .

Nota bahawa operasi penukaran boleh berkongsi DateTimeFormatter objek kerana yang DateTimeFormatter adalah thread selamat.

5.2. Mengintegrasikan Penyesuai Baru

Sekarang, mari ganti penyesuai lama dengan yang baru di kelas Buku kami dan juga Tarikh dengan Tempatan Tempatan :

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

Sekiranya kita menjalankan kod di atas, kita akan mendapat output:

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

Perhatikan bahawa LocalDateTime.toString () menambah pembatas "T" antara tarikh dan waktu.

6. Kesimpulannya

Dalam tutorial ini, kami meneroka tarikh penghapusan menggunakan JAXB .

Pertama, kami melihat pemetaan jenis data XML Schema to Java dan membuat contoh menggunakan format tarikh Skema XML lalai.

Seterusnya, kami belajar bagaimana menggunakan format tarikh khusus berdasarkan Adaptor Xml khusus dan melihat bagaimana menangani keselamatan utas SimpleDateFormat .

Akhirnya, kami memanfaatkan API Tarikh / Masa Java 8 yang unggul dan selamat untuk thread dan tarikh yang tidak disusun dengan format tersuai.

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