Bagaimana Anda menentukan format tanggal yang digunakan saat JAXB marshals xsd: dateTime?

87

Ketika JAXB menyusun objek tanggal ( XMLGregorianCalendar) ke dalam elemen xsd: dateTime. Bagaimana Anda bisa menentukan format XML yang dihasilkan?

Misalnya: Format data default menggunakan milidetik. <StartDate>2012-08-21T13:21:58.000Z</StartDate> Saya perlu menghilangkan milidetik. <StartDate>2012-08-21T13:21:58Z</StartDate>

Bagaimana saya bisa menentukan bentuk keluaran / format tanggal yang ingin saya gunakan? Saya menggunakan javax.xml.datatype.DatatypeFactoryuntuk membuat XMLGregorianCalendarobjek.

XMLGregorianCalendar xmlCal = datatypeFactory.newXMLGregorianCalendar(cal);
Fu muda
sumber

Jawaban:

127

Anda bisa menggunakan XmlAdapteruntuk menyesuaikan bagaimana tipe tanggal ditulis ke XML.

package com.example;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class DateAdapter extends XmlAdapter<String, Date> {

    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public String marshal(Date v) throws Exception {
        synchronized (dateFormat) {
            return dateFormat.format(v);
        }
    }

    @Override
    public Date unmarshal(String v) throws Exception {
        synchronized (dateFormat) {
            return dateFormat.parse(v);
        }
    }

}

Kemudian Anda menggunakan @XmlJavaTypeAdapteranotasi untuk menentukan bahwa XmlAdapterharus digunakan untuk bidang / properti tertentu.

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

Menggunakan file pengikat xjb:

<xjc:javaType name="java.util.Date" xmlType="xs:dateTime"
        adapter="com.example.DateAdapter"/>

akan menghasilkan penjelasan yang disebutkan di atas.
(Dengan akhirnya menambahkan xjcnamespace: xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc")

bdoughan.dll
sumber
2
Terima kasih atas jawaban ini! Apakah mungkin untuk menambahkan penjelasan melalui xsd atau file yang mengikat? Saya hanya menemukan entri blog Anda yang sering dikutip tentang bindings.xml, tetapi ini mencakup aspek lain, saya kira.
guerda
9
Seperti yang disebutkan @PeterRader, SimpleDateFormat tidak aman untuk thread - jika dua utas masuk ke marshal atau unmarshal secara bersamaan, Anda bisa mendapatkan hasil yang sangat tidak terduga. Ini akan sangat sulit untuk direproduksi dalam pengujian normal, tetapi di bawah beban dapat terjadi, dan akan sangat sulit untuk didiagnosis. Lebih baik membuat SimpleDateFormat baru dengan marshal dan unmarshal (tetapi gunakan string format statis jika perlu).
Colselaw
1
Saya melakukan ini dan hampir berhasil. Namun saya mendapatkan Class has two properties of the same name "timeSeries"kesalahan - ini diselesaikan dengan meletakkan anotasi di pengambil dan bukan di tingkat anggota. (Terima kasih kepada @megathor dari stackoverflow.com/questions/6768544/… )
gordon613
1
@ gordon613 - Artikel ini akan memberikan beberapa informasi tambahan tentang di mana harus meletakkan anotasi: blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
bdoughan
3
Karena blok kritis dilindungi dengan "disinkronkan" tidak ada masalah. Akan ada masalah (kinerja) jika beberapa panggilan dilakukan.
Mike Argyriou
17

Saya menggunakan SimpleDateFormat untuk membuat XMLGregorianCalendar, seperti dalam contoh ini:

public static XMLGregorianCalendar getXmlDate(Date date) throws DatatypeConfigurationException {
    return DatatypeFactory.newInstance().newXMLGregorianCalendar(new SimpleDateFormat("yyyy-MM-dd").format(date));
}

public static XMLGregorianCalendar getXmlDateTime(Date date) throws DatatypeConfigurationException {
    return DatatypeFactory.newInstance().newXMLGregorianCalendar(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(date));
}

Metode pertama membuat instance XMLGregorianCalendar yang diformat oleh XML marshaller sebagai tanggal xsd: valid, metode kedua menghasilkan xsd: dateTime yang valid.

Andrea Luciano
sumber
2

Cara yang sangat mudah untuk saya. Memformat XMLGregorianCalendar untuk marshalling di java.

Saya baru saja membuat data saya dalam format yang baik. The toStringakan disebut memproduksi hasil yang baik.

public static final XMLGregorianCalendar getDate(Date d) {
    try {
        return DatatypeFactory.newInstance().newXMLGregorianCalendar(new SimpleDateFormat("yyyy-MM-dd").format(d));
    } catch (DatatypeConfigurationException e) {
        return null;
    }
}
Iván
sumber
1

https://www.baeldung.com/jaxb

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);
    }
}
Mike
sumber
0

Pemakaian:

import com.company.LocalDateAdapter.yyyyMMdd;
...

@XmlElement(name = "PROC-DATE")
@XmlJavaTypeAdapter(yyyyMMdd.class)
private LocalDate processingDate;

LocalDateAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class LocalDateAdapter extends XmlAdapter<String, LocalDate> {

    public static final class yyyyMMdd extends LocalDateAdapter {
        public yyyyMMdd() {
            super("yyyyMMdd");
        }
    }

    public static final class yyyy_MM_dd extends LocalDateAdapter {
        public yyyy_MM_dd() {
            super("yyyy-MM-dd");
        }
    }

    private final DateTimeFormatter formatter;

    public LocalDateAdapter(String pattern) {
        formatter = DateTimeFormat.forPattern(pattern);
    }

    @Override
    public String marshal(LocalDate date) throws Exception {
        return formatter.print(date);
    }

    @Override
    public LocalDate unmarshal(String date) throws Exception {
        return formatter.parseLocalDate(date);
    }
}
Mike
sumber