Просте перетворення між java.util.Date та XMLGregorianCalendar


110

Я шукаю простий метод перетворення між java.util.Date і javax.xml.datatype.XMLGregorianCalendar в обох напрямках.

Ось код, який я зараз використовую :

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

Чи є щось простіше, як-от якийсь дзвінок API, який я не помітив?

Перетворення між стандартною датою / часом XML і об'єктом дати Java здається досить звичайною задачею, і я здивований, що мені взагалі доводиться писати цей код.

Будь-які пропозиції?

ПРИМІТКИ. Мої класи JAXB автоматично генеруються зі схеми. Процес збирання мого проекту не дозволяє мені вносити вручну зміни в створені класи. Елементи xs: dateTime генеруються XJC як XMLGregorianCalendar в класах JAXB. Схему періодично розширюють і переробляють, тому мені дозволяється вносити обмежені зміни у файл XSD схеми.

ОНОВЛЕННЯ РІШЕННЯ: Рішення, запропоноване Blaise, дозволило мені вийняти XMLGregorianCalendar із суміші та замість цього обробляти об'єкти java.util.Calendar. Додавши прив'язуючий пункт JAXB у верхній частині мого файлу схеми, XJC може генерувати більш відповідні відображення для xs: dateTime у моїх класах JAXB. Ось кілька фрагментів, які показують зміни в моєму файлі XSD.

Кореневий елемент у файлі 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">

Блок анотації зв’язування JAXB, вставлений одразу після кореневого елемента в 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>

Оскільки поле XML xs: dateTime також зберігає часовий пояс, для мене може бути краще працювати з календарем, а не з датою, оскільки об’єкти календаря мають досить хороший API для роботи з локалями та часовими поясами. У будь-якому випадку, я набагато щасливіше мати справу з об’єктами календаря замість XMLGregorianCalendar. Більше не потрібно методів перетворення, які я перераховував вище. Я не пробрався до java.util.Date, але досить близько!


Я не знаю жодного. Але ваше здається досить чудовим - просто помістіть його в utilпакет і використовуйте.
Божо

Сортування вбік, але навіщо вам в першу чергу мати справу з об'єктами XMLGregorianCalendar? Вони щось дратують. Якщо вони надходять з jaxb, можна використовувати @XMLTypeAdapter для прив’язки безпосередньо до java.util.Date. Звичайно, якщо ви автогенеруєте схему, зміна об'єктів може бути настільки ж дратівливою, коли ви регенеруєте.
Affe

@Affe Я автоматично генерую схему, тому я не можу вносити жодних ручних змін до створених класів JAXB
Jim Tough


1
@Jacob - це не так. Він уже придумав, як це зробити, і цікавиться, чи не існує готового до використання класу корисності.
Божо

Відповіді:


46

Чому б не використати зовнішній прив’язуючий файл, щоб сказати XJC для генерації полів java.util.Date замість XMLGregorianCalendar?

Також дивіться Як відобразити xs: date to java.util.Date? Блог


Я розберуся в цьому. Дякую.
Jim Tough

Нема проблем. JAXB може працювати з типом java.util.Date, потрібно просто створити його у своїй моделі. Що може бути складним.
bdoughan

Це вийшло для мене. Докладніше про те, що я зробив, перегляньте зміни до мого питання вище
Jim Tough

Я додав прив'язки jaxb, але прямо під xs: схему, і я отримую таку помилку: com.sun.istack.SAXParseException2: компілятор не зміг виконати цю налаштування глобальних зв'язків. Він прикріплений до неправильного місця або його несумісності з іншими прив’язками. на com.sun.tools.xjc.ErrorReceiver.error (ErrorReceiver.java:86) о ..
при

@pritam - Ось ще один приклад, який може допомогти: blog.bdoughan.com/2011/08/xml-schema-to-java-generating.html . Можливо, варто переглянути нове запитання щодо проблеми, яку ви бачите.
bdoughan

81

Від XMLGregorianCalendar до java.util.Date ви можете просто зробити:

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

Дякую ... Я шукав спосіб перетворити XMLGregorianCalendar на час у мілі.
Andez

6

З java.util.Date в XMLGregorianCalendar ви можете просто зробити:

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

Код відредагований після першого коментаря @ f-puras, тому що я помиляюся.


1
Не працює так, як ви це написали: GregorianCalendar.setTime () нічого не поверне.
f_puras

5

Мені довелося внести деякі зміни, щоб це працювало, оскільки, здається, деякі речі тим часом змінилися:

  • xjc скаржиться, що мій адаптер не поширює XmlAdapter
  • деякі химерні та непотрібні імпорти були залучені (org.w3._2001.xmlschema)
  • методи розбору не повинні бути статичними при розширенні XmlAdapter, очевидно

Ось робочий приклад, сподіваюся, що це допоможе (я використовую JodaTime, але в цьому випадку SimpleDate буде достатньо):

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

У xsd я дотримувався чудових посилань, наведених вище, тому я включив цю примітку xml:

<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
Я став шанувальником Joda Time за час, коли я поставив це питання. Настільки краще, ніж дати та часові класи Java SE. Дивовижно для обробки часових поясів!
Джим Трудний

1

У мене теж був такий головний біль. Позбувся цього, просто представивши часові поля як примітивні довгі в моєму POJO. Тепер покоління мого клієнтського коду WS обробляє все правильно і більше не лайно XML до Java. І звичайно мати справу з мілі на стороні Java просто і безболісно. Принцип KISS скелі!


1

За допомогою цієї настройки можна змінити відображення за замовчуванням на 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

Налаштування календаря та дати під час маршалінгу

Крок 1: Підготуйте xx для прив'язки xx для спеціальних властивостей. У цьому випадку я підготувався до дати та календаря

<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" />


Налаштування 2: Додайте користувацький файл прив'язки jaxb до Apache або будь-яких пов'язаних плагінів за допомогою параметра xsd, як зазначено нижче

<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>

Налаштування 3: запишіть код для класу 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);
    }
}

Установка 4: Вихід

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

   <fileDate>2014-09-25</fileDate> - Date class formatted
</xmlHeader>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.