Chuyển đổi đơn giản giữa java.util.Date và XMLGregorianCalendar


110

Tôi đang tìm một phương pháp đơn giản để chuyển đổi giữa java.util.Date và javax.xml.datatype.XMLGregorianCalendar theo cả hai hướng.

Đây là mã mà tôi đang sử dụng bây giờ :

import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 * Utility class for converting between XMLGregorianCalendar and java.util.Date
 */
public class XMLGregorianCalendarConverter {  

    /**
     * Needed to create XMLGregorianCalendar instances
     */
    private static DatatypeFactory df = null;
    static {
        try {
            df = DatatypeFactory.newInstance();
        } catch (DatatypeConfigurationException dce) {
            throw new IllegalStateException(
                "Exception while obtaining DatatypeFactory instance", dce);
        }
    }  

    /**
     * Converts a java.util.Date into an instance of XMLGregorianCalendar
     *
     * @param date Instance of java.util.Date or a null reference
     * @return XMLGregorianCalendar instance whose value is based upon the
     *  value in the date parameter. If the date parameter is null then
     *  this method will simply return null.
     */
    public static XMLGregorianCalendar asXMLGregorianCalendar(java.util.Date date) {
        if (date == null) {
            return null;
        } else {
            GregorianCalendar gc = new GregorianCalendar();
            gc.setTimeInMillis(date.getTime());
            return df.newXMLGregorianCalendar(gc);
        }
    }

    /**
     * Converts an XMLGregorianCalendar to an instance of java.util.Date
     *
     * @param xgc Instance of XMLGregorianCalendar or a null reference
     * @return java.util.Date instance whose value is based upon the
     *  value in the xgc parameter. If the xgc parameter is null then
     *  this method will simply return null.
     */
    public static java.util.Date asDate(XMLGregorianCalendar xgc) {
        if (xgc == null) {
            return null;
        } else {
            return xgc.toGregorianCalendar().getTime();
        }
    }
}

Có điều gì đơn giản hơn, như một số lệnh gọi API mà tôi đã bỏ qua không?

Chuyển đổi giữa một ngày / giờ XML chuẩn và một đối tượng ngày trong Java có vẻ như là một nhiệm vụ khá thường xuyên và tôi ngạc nhiên rằng tôi phải viết mã này.

Bất kỳ đề xuất?

LƯU Ý: Các lớp JAXB của tôi được tạo tự động từ một lược đồ. Quá trình xây dựng trên dự án của tôi không cho phép tôi thực hiện các thay đổi thủ công đối với các lớp đã tạo. Các phần tử xs: dateTime đang được tạo bởi XJC dưới dạng XMLGregorianCalendar trong các lớp JAXB. Lược đồ được mở rộng và chỉnh sửa định kỳ, vì vậy tôi được phép thực hiện các thay đổi hạn chế đối với tệp XSD của lược đồ.

CẬP NHẬT GIẢI PHÁP: Giải pháp do Blaise đề xuất đã cho phép tôi đưa XMLGregorianCalendar ra khỏi hỗn hợp và xử lý các đối tượng java.util.Calendar để thay thế. Bằng cách thêm mệnh đề ràng buộc JAXB ở đầu tệp lược đồ của tôi, XJC có thể tạo các ánh xạ thích hợp hơn cho xs: dateTime trong các lớp JAXB của tôi. Dưới đây là một số đoạn mã hiển thị các sửa đổi trong tệp XSD của tôi.

Phần tử gốc trong tệp XSD:

<xs:schema xmlns:mydata="http://my.example.com/mydata" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" targetNamespace="http://my.example.com/mydata" elementFormDefault="unqualified" attributeFormDefault="unqualified" version="0.2" xml:lang="en" jaxb:version="2.0">

Khối chú thích liên kết JAXB, được chèn ngay sau phần tử gốc trong XSD:

<xs:annotation>
    <xs:appinfo>
        <jaxb:globalBindings>
            <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime" parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime" printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
        </jaxb:globalBindings>
    </xs:appinfo>
</xs:annotation>

Vì trường XML xs: dateTime cũng lưu trữ múi giờ, tốt hơn là tôi nên làm việc với Lịch thay vì Ngày vì các đối tượng Lịch có một API khá tốt để làm việc với các ngôn ngữ và múi giờ. Trong mọi trường hợp, tôi hạnh phúc hơn nhiều khi xử lý các đối tượng Lịch thay vì XMLGregorianCalendar. Không cần các phương pháp chuyển đổi mà tôi đã liệt kê ở trên nữa. Tôi không hiểu được tất cả các cách để java.util.Date, nhưng đủ gần!


Tôi không biết bất kỳ. Nhưng của bạn có vẻ khá ổn - chỉ cần đặt nó trong một utilgói và sử dụng nó.
Bozho

Bỏ qua một bên, nhưng tại sao bạn phải xử lý các đối tượng XMLGregorianCalendar ngay từ đầu? Chúng hơi khó chịu. Nếu chúng đến từ jaxb, bạn có thể sử dụng @XMLTypeAdapter để liên kết trực tiếp với java.util.Date. Tất nhiên nếu bạn đang tự động tạo ra một lược đồ, việc thay đổi các đối tượng có thể gây khó chịu như khi bạn tạo lại.
Affe

@Affe Tôi đang tự động tạo ra khỏi một lược đồ nên tôi không thể thực hiện bất kỳ thay đổi thủ công nào đối với các lớp JAXB đã tạo
Jim Tough

Điều này có giống với stackoverflow.com/questions/835889/… không?
Jacob Tomaw

1
@Jacob - không phải vậy. Anh ấy đã tìm ra cách làm điều đó, anh ấy tự hỏi liệu có phải không có một lớp tiện ích sẵn sàng sử dụng hay không.
Bozho

Câu trả lời:


46

Tại sao không sử dụng tệp liên kết bên ngoài để yêu cầu XJC tạo các trường java.util.Date thay vì XMLGregorianCalendar?

Cũng xem Làm cách nào để ánh xạ xs: date với java.util.Date? Blog


Tôi sẽ xem xét này. Cảm ơn.
Jim Tough

Không vấn đề gì. JAXB có thể xử lý kiểu java.util.Date, bạn chỉ cần tạo nó trong mô hình của mình. Có thể là khó khăn.
bdoughan

Điều đó đã làm việc cho tôi. Xem các chỉnh sửa cho câu hỏi của tôi ở trên để biết chi tiết về những gì tôi đã làm.
Jim Tough

Tôi đã thêm liên kết jaxb nhưng ngay bên dưới xs: schema và tôi gặp lỗi sau: com.sun.istack.SAXParseException2: trình biên dịch không thể đáp ứng tùy chỉnh globalBindings này. Nó được gắn vào một nơi sai, hoặc không phù hợp với các ràng buộc khác. tại com.sun.tools.xjc.ErrorReceiver.error (ErrorReceiver.java:86) lúc ..
pri

@ scamam - Đây là một ví dụ khác có thể hữu ích: blog.bdoughan.com/2011/08/xml-schema-to-java-generating.html . Có thể đáng để đặt một câu hỏi mới cho vấn đề bạn đang gặp phải.
bdoughan

81

Từ XMLGregorianCalendar sang java.util.Date, bạn chỉ cần thực hiện:

java.util.Date dt = xmlGregorianCalendarInstance.toGregorianCalendar().getTime();  

Cảm ơn ... Tôi đang tìm cách chuyển đổi XMLGregorianCalendar thành thời gian tính bằng mili giây.
Andez

6

Từ java.util.Date sang XMLGregorianCalendar, bạn chỉ cần thực hiện:

import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
import java.util.GregorianCalendar;
......
GregorianCalendar gcalendar = new GregorianCalendar();
gcalendar.setTime(yourDate);
XMLGregorianCalendar xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcalendar);

Mã được chỉnh sửa sau nhận xét đầu tiên của @ f-puras, do tôi làm sai.


1
Không hoạt động theo cách bạn đã viết: GregorianCalendar.setTime () sẽ không trả về bất kỳ thứ gì.
f_puras,

5

Tôi đã phải thực hiện một số thay đổi để làm cho nó hoạt động, vì một số thứ dường như đã thay đổi trong thời gian chờ đợi:

  • xjc sẽ phàn nàn rằng bộ điều hợp của tôi không mở rộng XmlAdapter
  • một số nội dung nhập kỳ lạ và không cần thiết đã được đưa vào (org.w3._2001.xmlschema)
  • các phương thức phân tích cú pháp không được tĩnh khi mở rộng XmlAdapter, rõ ràng

Đây là một ví dụ hoạt động, hy vọng điều này sẽ hữu ích (Tôi đang sử dụng JodaTime nhưng trong trường hợp này thì SimpleDate là đủ):

import java.util.Date;
import javax.xml.bind.DatatypeConverter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.joda.time.DateTime;

public class DateAdapter extends XmlAdapter<Object, Object> {
    @Override
    public Object marshal(Object dt) throws Exception {
        return new DateTime((Date) dt).toString("YYYY-MM-dd");
    }

    @Override
        public Object unmarshal(Object s) throws Exception {
        return DatatypeConverter.parseDate((String) s).getTime();
    }
}

Trong xsd, tôi đã theo dõi các tài liệu tham khảo tuyệt vời được đưa ra ở trên, vì vậy tôi đã bao gồm chú thích xml này:

<xsd:appinfo>
    <jaxb:schemaBindings>
        <jaxb:package name="at.mycomp.xml" />
    </jaxb:schemaBindings>
    <jaxb:globalBindings>
        <jaxb:javaType name="java.util.Date" xmlType="xsd:date"
              parseMethod="at.mycomp.xml.DateAdapter.unmarshal"
          printMethod="at.mycomp.xml.DateAdapter.marshal" />
    </jaxb:globalBindings>
</xsd:appinfo>

1
Tôi đã trở thành một người hâm mộ Joda Time kể từ khi tôi đặt câu hỏi này. Tốt hơn nhiều so với các lớp ngày và giờ trong Java SE. Tuyệt vời để xử lý múi giờ!
Jim Tough

1

Tôi cũng đã có loại đau đầu này. Đã loại bỏ nó bằng cách đơn giản biểu diễn các trường thời gian dài như nguyên thủy trong POJO của tôi. Giờ đây, thế hệ mã khách hàng WS của tôi xử lý mọi thứ một cách chính xác và không còn lỗi chuyển XML sang Java nữa. Và tất nhiên việc xử lý mili trên Java rất đơn giản và không gây đau đớn. KISS đá nguyên lý!


1

Bạn có thể sử dụng tùy chỉnh này để thay đổi ánh xạ mặc định thành java.util.Date

<xsd:annotation>
<xsd:appinfo>
    <jaxb:globalBindings>
        <jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime"
                 parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime"
                 printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime"/>
    </jaxb:globalBindings>
</xsd:appinfo>


0

Tùy chỉnh Lịch và Ngày trong khi Marshaling

Bước 1: Chuẩn bị xml ràng buộc jaxb cho các thuộc tính tùy chỉnh, Trong trường hợp này, tôi đã chuẩn bị cho ngày và lịch

<jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jaxb:globalBindings generateElementProperty="false">
<jaxb:serializable uid="1" />
<jaxb:javaType name="java.util.Date" xmlType="xs:date"
    parseMethod="org.apache.cxf.tools.common.DataTypeAdapter.parseDate"
    printMethod="com.stech.jaxb.util.CalendarTypeConverter.printDate" />
<jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
    parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
    printMethod="com.stech.jaxb.util.CalendarTypeConverter.printCalendar" />


Setp 2: Thêm tệp ràng buộc jaxb tùy chỉnh vào Apache hoặc bất kỳ plugin nào liên quan tại tùy chọn xsd như được đề cập bên dưới

<xsdOption>
  <xsd>${project.basedir}/src/main/resources/tutorial/xsd/yourxsdfile.xsd</xsd>
  <packagename>com.tutorial.xml.packagename</packagename>
  <bindingFile>${project.basedir}/src/main/resources/xsd/jaxbbindings.xml</bindingFile>
</xsdOption>

Setp 3: Viết mã cho lớp CalendarConverter

package com.stech.jaxb.util;

import java.text.SimpleDateFormat;

/**
 * To convert the calendar to JaxB customer format.
 * 
 */

public final class CalendarTypeConverter {

    /**
     * Calendar to custom format print to XML.
     * 
     * @param val
     * @return
     */
    public static String printCalendar(java.util.Calendar val) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss");
        return simpleDateFormat.format(val.getTime());
    }

    /**
     * Date to custom format print to XML.
     * 
     * @param val
     * @return
     */
    public static String printDate(java.util.Date val) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        return simpleDateFormat.format(val);
    }
}

Setp 4: Đầu ra

  <xmlHeader>
   <creationTime>2014-09-25T07:23:05</creationTime> Calendar class formatted

   <fileDate>2014-09-25</fileDate> - Date class formatted
</xmlHeader>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.