2010-09-09 11 views
106

Szukam prostej metody konwersji między java.util.Date i javax.xml.datatype.XMLGregorianCalendar w obie strony.Prosta konwersja między java.util.Date i XMLGregorianCalendar

Oto kod, który używam teraz:

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

Czy jest coś prostszego, jak niektórzy nazywają API że przeoczyliśmy?

Konwersja pomiędzy standardową datą/czasem XML a obiektem daty Java wydaje się być całkiem rutynowym zadaniem i jestem zaskoczony, że muszę napisać ten kod w ogóle.

Wszelkie sugestie?

UWAGI: Moje klasy JAXB są generowane automatycznie ze schematu. Proces kompilacji w moim projekcie nie pozwala mi ręcznie wprowadzać zmian w wygenerowanych klasach. Elementy XS: dateTime są generowane przez XJC jako XMLGregorianCalendar w klasach JAXB. Schemat jest okresowo rozszerzany i modyfikowany, więc mogę wprowadzać ograniczone zmiany do pliku XSD schematu.

UPDATE ROZWIĄZANIE: Proponowana przez Błażeja rozwiązanie pozwoliło mi podjąć XMLGregorianCalendar z mieszanki i radzić sobie z java.util.Calendar obiektów zamiast. Dodając klauzulę wiążącą JAXB u góry mojego pliku schematu, XJC jest w stanie wygenerować bardziej odpowiednie odwzorowania dla xs: dateTime w moich klasach JAXB. Oto kilka fragmentów pokazujących modyfikacje w moim pliku XSD.

elementem głównym pliku 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 wiązania bloku adnotacji umieszczonej bezpośrednio za elementem głównym 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> 

Ponieważ xs XML: pola daty również przechowuje strefę czasową, może lepiej dla mnie pracować z Kalendarzem zamiast Datą, ponieważ obiekty Kalendarza mają całkiem niezły interfejs API do pracy z ustawieniami regionalnymi i strefami czasowymi. W każdym razie cieszę się, że mogę zajmować się obiektami kalendarza zamiast XMLGregorianCalendar. Nie ma już potrzeby stosowania metod konwersji wymienionych powyżej. Nie dotarłem aż do java.util.Date, ale wystarczająco blisko!

+0

Co na marginesie, ale dlaczego w pierwszej kolejności zajmujesz się obiektami XMLGregorianCalendar? Są trochę irytujące. Jeśli pochodzą one z jaxb, możliwe jest użycie @XMLTypeAdapter do bezpośredniego powiązania z java.util.Date. Oczywiście, jeśli generujesz autogenerację schematu, zmiana obiektów może być równie irytująca podczas regeneracji. – Affe

+0

@Affe Generuję autogenerację schematu, więc nie mogę wprowadzić żadnych ręcznych zmian w wygenerowanych klasach JAXB. –

+0

Czy jest to to samo, co http://stackoverflow.com/questions/835889/java-util-date-to -xmlgregoriancalendar? –

Odpowiedz

44

Dlaczego nie używać zewnętrznego pliku powiązań, aby nakazać XJC generowanie pól java.util.Date zamiast XMLGregorianCalendar?

zobacz także: - http://weblogs.java.net/blog/kohsuke/archive/2006/03/how_do_i_map_xs.html

+0

Zajrzę do tego. Dzięki. –

+0

Bez problemu. JAXB może obsłużyć typ java.util.Date, wystarczy go wygenerować w swoim modelu. Co może być trudne. –

+0

To mi się udało. Zobacz zmiany na moje pytanie powyżej, aby uzyskać szczegółowe informacje o tym, co zrobiłem. –

5

Musiałem dokonać pewnych zmian, aby to działało, jak pewne rzeczy wydają się zmieniło w międzyczasie:

  • XJC będzie skarżą się, że moja karta nie przedłużyć XmlAdapter
  • niektóre dziwne i niepotrzebne przywóz zostały wykorzystane w (org.w3._2001.XMLSchema)
  • metody analizowania nie muszą być statyczne, gdy rozszerzenie XmlAdapter oczywiście

Oto przykład pracy, mam nadzieję, że to pomaga (używam JodaTime ale w tym przypadku SimpleDate byłoby wystarczające):

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

W XSD I następuje doskonałe odniesienia podane powyżej, więc nie zostały włączone XML'u adnotacji:

<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

Stałem się Fanów Joda Time, odkąd zadałem to pytanie. O wiele lepiej niż klasy daty i czasu Java SE. Świetny do obsługi stref czasowych! –

1

Też miałem ten rodzaj bólu głowy. Pozbyłem się tego, po prostu reprezentując pola czasu jako prymitywne w moim POJO. Teraz generowanie mojego kodu klienta WS radzi sobie z wszystkim poprawnie i nie ma więcej bzdur XML-to-Java. I oczywiście zajmowanie się millis po stronie Java jest proste i bezbolesne. KISS zasada skały!

79

Od XMLGregorianCalendar do java.util.Date można po prostu zrobić:

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

Dzięki ... Szukałem sposobu na konwersję XMLGregorianCalendar na czas w milisach. – Andez

6

Od java.util.Date do XMLGregorianCalendar można po prostu zrobić:

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

kod edytowanego po pierwszym komentarzu z @ f-puras, ponieważ ja popełniam błąd.

+1

Nie działa tak, jak to napisałeś: GregorianCalendar.setTime() nic nie zwróci. –

0

Dostosowywanie kalendarza i datę, a Organizowanie

Etap 1: Przygotowanie JAXB wiązania xml na właściwości niestandardowych W tym przypadku przygotowane daty i kalendarza

<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 : Dodaj niestandardowy plik powiązania jaxb do Apache lub dowolne powiązane wtyczki w opcji xsd, jak wspomniano poniżej:

<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: napisać kod CalendarConverter klasy

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: wyjście

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

    <fileDate>2014-09-25</fileDate> - Date class formatted 
</xmlHeader> 
1

Można użyć tej dostosowanie do zmiany domyślnego mapowania 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> 

Powiązane problemy