คุณระบุรูปแบบวันที่ที่ใช้เมื่อ JAXB marshals xsd: dateTime ได้อย่างไร


87

เมื่อ JAXB จัดXMLGregorianCalendarระเบียบวัตถุวันที่ ( ) เป็นองค์ประกอบ xsd: dateTime คุณสามารถระบุรูปแบบของ XML ที่เป็นผลลัพธ์ได้อย่างไร?

ตัวอย่างเช่น: รูปแบบข้อมูลเริ่มต้นใช้มิลลิวินาที<StartDate>2012-08-21T13:21:58.000Z</StartDate> ฉันต้องเว้นมิลลิวินาที <StartDate>2012-08-21T13:21:58Z</StartDate>

ฉันจะระบุรูปแบบผลลัพธ์ / รูปแบบวันที่ที่ฉันต้องการใช้ได้อย่างไร ฉันใช้javax.xml.datatype.DatatypeFactoryสร้างXMLGregorianCalendarวัตถุ

XMLGregorianCalendar xmlCal = datatypeFactory.newXMLGregorianCalendar(cal);

คำตอบ:


127

คุณสามารถใช้XmlAdapterเพื่อกำหนดวิธีเขียนประเภทวันที่ลงใน 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);
        }
    }

}

จากนั้นคุณใช้@XmlJavaTypeAdapterคำอธิบายประกอบเพื่อระบุว่าXmlAdapterควรใช้สำหรับฟิลด์ / คุณสมบัติเฉพาะ

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

การใช้ไฟล์การรวม xjb:

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

จะจัดทำคำอธิบายประกอบดังกล่าวข้างต้น
(โดยในที่สุดเพิ่มxjcnamespace: xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc")


2
ขอบคุณสำหรับคำตอบนี้! เป็นไปได้ไหมที่จะเพิ่มคำอธิบายประกอบผ่าน xsd หรือไฟล์ที่มีผลผูกพัน ฉันพบเฉพาะรายการบล็อกที่คุณอ้างถึงบ่อยๆเกี่ยวกับ bindings.xml แต่ฉันคิดว่าสิ่งนี้ครอบคลุมด้านอื่น ๆ
guerda

9
ดังที่ @PeterRader กล่าวไว้ SimpleDateFormat ไม่ปลอดภัยต่อเธรด - หากสองเธรดเข้าสู่ marshal หรือ unmarshal พร้อมกันคุณอาจได้ผลลัพธ์ที่ไม่สามารถคาดเดาได้ นี่จะเป็นเรื่องยากมากที่จะทำซ้ำในการทดสอบปกติ แต่อาจเกิดขึ้นภายใต้ภาระได้และยากที่จะวินิจฉัย การสร้าง SimpleDateFormat ใหม่ด้วย marshal และ unmarshal จะดีกว่า (แต่ให้ใช้สตริงรูปแบบคงที่หากจำเป็น)
Colselaw

1
ฉันทำสิ่งนี้และเกือบจะได้ผล อย่างไรก็ตามฉันได้รับClass has two properties of the same name "timeSeries"ข้อผิดพลาด - แก้ไขได้โดยใส่คำอธิบายประกอบที่ getter ไม่ใช่ในระดับสมาชิก (ขอบคุณข้อมูลจาก @megathor stackoverflow.com/questions/6768544/… )
gordon613

1
@ gordon613 - บทความนี้จะให้ข้อมูลเพิ่มเติมเกี่ยวกับตำแหน่งที่จะใส่คำอธิบายประกอบ: blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
bdoughan

3
เนื่องจากบล็อกวิกฤตได้รับการป้องกันด้วย "ซิงโครไนซ์" จึงไม่มีปัญหาใด ๆ จะมีปัญหา (ประสิทธิภาพ) หากมีการโทรหลายครั้ง
Mike Argyriou

17

ฉันใช้ SimpleDateFormat เพื่อสร้าง XMLGregorianCalendar เช่นในตัวอย่างนี้:

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

วิธีแรกสร้างอินสแตนซ์ของ XMLGregorianCalendar ที่จัดรูปแบบโดย XML marshaller เป็น xsd: date ที่ถูกต้องวิธีที่สองจะส่งผลให้ xsd: dateTime ถูกต้อง


2

วิธีที่ง่ายมากสำหรับฉัน การจัดรูปแบบ XMLGregorianCalendar สำหรับ marshalling ใน java

ฉันเพิ่งสร้างข้อมูลของฉันในรูปแบบที่ดี toStringจะถูกเรียกว่าที่ให้ผลดี

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

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

0

การใช้งาน:

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);
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.