2010-09-09 7 views
106

Я ищу простой способ преобразования между java.util.Date и javax.xml.datatype.XMLGregorianCalendar в обоих направлениях.Простое преобразование между java.util.Date и 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 схемы.

ОБНОВЛЕНИЕ НА РЕШЕНИЕ: Решение, предложенное Блейза позволило мне взять 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 хз: DateTime поле также хранит часовой пояс, мне может быть лучше работать с Calendar вместо Date, так как объекты Calendar имеют довольно хороший API для работы с локалями и часовыми поясами. В любом случае, я гораздо счастливее иметь дело с объектами Calendar вместо XMLGregorianCalendar. Нет необходимости в методах преобразования, которые я выше перечислял выше. Я не добрался до java.util.Date, но достаточно близко!

+0

Отклонение в сторону, но почему вам приходится иметь дело с объектами XMLGregorianCalendar в первую очередь? Они раздражают. Если они происходят из jaxb, можно использовать @XMLTypeAdapter для непосредственного привязки к java.util.Date. Конечно, если вы автоматически генерируете схему, изменение объектов может быть столь же раздражающим, когда вы регенерируете. – Affe

+0

@Affe Я автоматически генерирую схему, поэтому я не могу внести никаких изменений вручную в созданные классы JAXB. –

+0

Является ли это таким же, как http://stackoverflow.com/questions/835889/java-util-date-to -xmlgregoriancalendar? –

ответ

44

Почему бы не использовать внешний файл привязки, чтобы сообщить XJC о создании полей java.util.Date вместо XMLGregorianCalendar?

Смотрите также: - http://weblogs.java.net/blog/kohsuke/archive/2006/03/how_do_i_map_xs.html

+0

Я рассмотрю это. Благодарю. –

+0

Нет проблем. JAXB может обрабатывать тип java.util.Date, вам просто нужно сгенерировать его в своей модели. Это может быть сложно. –

+0

Это сработало для меня. См. Изменения в моем вопросе выше для получения подробной информации о том, что я сделал. –

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-to-Java. И, конечно, дело с millis на стороне Java простое и безболезненное. KISS принцип камни!

79

От XMLGregorianCalendar к java.util.Date вы можете просто сделать:

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

Спасибо ... Я искал способ конвертировать 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() ничего не вернет. –

0

Настройка календаря и даты, а Маршалинг

Шаг 1: Подготовка JAXB связывания XML для пользовательских свойств, в этом случае я, подготовленный для даты и календарь

<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 : Добавить пользовательский файл привязки 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> 

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

Setp 4: Выход

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

    <fileDate>2014-09-25</fileDate> - Date class formatted 
</xmlHeader> 
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> 

Смежные вопросы