Einfache Konvertierung zwischen java.util.Date und XMLGregorianCalendar


110

Ich suche nach einer einfachen Methode zum Konvertieren zwischen java.util.Date und javax.xml.datatype.XMLGregorianCalendar in beide Richtungen.

Hier ist der Code, den ich jetzt verwende :

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

Gibt es etwas Einfacheres, wie einen API-Aufruf, den ich übersehen habe?

Das Konvertieren zwischen einem Standard-XML-Datums- / Uhrzeit- und einem Java-Datumsobjekt scheint eine ziemlich routinemäßige Aufgabe zu sein, und ich bin überrascht, dass ich diesen Code überhaupt schreiben muss.

Irgendwelche Vorschläge?

HINWEISE: Meine JAXB-Klassen werden automatisch aus einem Schema generiert. Der Erstellungsprozess in meinem Projekt ermöglicht es mir nicht, manuelle Änderungen an den generierten Klassen vorzunehmen. Die xs: dateTime-Elemente werden von XJC als XMLGregorianCalendar in den JAXB-Klassen generiert. Das Schema wird regelmäßig erweitert und optimiert, sodass ich nur begrenzte Änderungen an der XSD-Schemadatei vornehmen darf.

UPDATE ON SOLUTION: Die von Blaise vorgeschlagene Lösung hat es mir ermöglicht, XMLGregorianCalendar aus dem Mix zu nehmen und stattdessen mit java.util.Calendar-Objekten umzugehen. Durch Hinzufügen einer JAXB-Bindungsklausel oben in meiner Schemadatei kann XJC in meinen JAXB-Klassen geeignetere Zuordnungen für xs: dateTime generieren. Hier sind einige Ausschnitte, die die Änderungen in meiner XSD-Datei zeigen.

Das Stammelement in der XSD-Datei:

<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-Bindungsanmerkungsblock, der unmittelbar nach dem Stammelement in XSD eingefügt wird:

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

Da im XML xs: dateTime-Feld auch die Zeitzone gespeichert ist, ist es für mich möglicherweise besser, mit Kalender anstelle von Datum zu arbeiten, da Kalenderobjekte eine ziemlich gute API für die Arbeit mit Gebietsschemas und Zeitzonen haben. Auf jeden Fall bin ich viel glücklicher mit Kalenderobjekten als mit XMLGregorianCalendar umzugehen. Die oben aufgeführten Konvertierungsmethoden sind nicht mehr erforderlich. Ich bin nicht bis zu java.util.Date gekommen, aber nah genug!


Ich kenne keine. Aber deins scheint ziemlich in Ordnung zu sein - lege es einfach in eine utilPackung und benutze es.
Bozho

Eine Art Nebeneffekt, aber warum müssen Sie sich überhaupt mit XMLGregorianCalendar-Objekten befassen? Sie sind irgendwie irritierend. Wenn sie von jaxb stammen, können Sie mit @XMLTypeAdapter direkt an java.util.Date binden. Wenn Sie aus einem Schema automatisch generieren, kann das Ändern der Objekte beim Regenerieren natürlich genauso irritierend sein.
Affe

@Affe Ich generiere automatisch aus einem Schema, so dass ich keine manuellen Änderungen an den generierten JAXB-Klassen vornehmen kann
Jim Tough


1
@ Jacob - ist es nicht. Er hat bereits herausgefunden, wie es geht, und fragt sich, ob es keine gebrauchsfertige Utility-Klasse gibt.
Bozho

Antworten:


46

Warum nicht eine externe Bindungsdatei verwenden, um XJC anzuweisen, java.util.Date-Felder anstelle von XMLGregorianCalendar zu generieren?

Siehe auch Wie ordne ich xs: date java.util.Date zu? Blog


Ich werde das untersuchen. Vielen Dank.
Jim Tough

Kein Problem. JAXB kann den Typ java.util.Date verarbeiten. Sie müssen ihn nur in Ihrem Modell generieren. Welches kann schwierig sein.
Bdoughan

Das hat bei mir geklappt. Einzelheiten zu meiner Arbeit finden Sie oben unter Änderungen an meiner Frage.
Jim Tough

Ich habe Jaxb-Bindungen hinzugefügt, aber direkt unter xs: schema und erhalte die folgende Fehlermeldung: com.sun.istack.SAXParseException2: Der Compiler konnte diese globalBindings-Anpassung nicht berücksichtigen. Es ist an einer falschen Stelle angebracht oder nicht mit anderen Bindungen vereinbar. at com.sun.tools.xjc.ErrorReceiver.error (ErrorReceiver.java:86) at ..
pri

@pritam - Hier ist ein weiteres Beispiel, das helfen kann: blog.bdoughan.com/2011/08/xml-schema-to-java-generating.html . Es kann sich lohnen, eine neue Frage für das Problem zu stellen, das Sie sehen.
Bdoughan

81

Von XMLGregorianCalendar bis java.util.Date können Sie einfach Folgendes tun:

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

Danke ... Ich suchte nach einer Möglichkeit, XMLGregorianCalendar in Millis in Zeit umzuwandeln.
Andez

6

Von java.util.Date bis XMLGregorianCalendar können Sie einfach Folgendes tun:

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

Code bearbeitet nach dem ersten Kommentar von @ f-puras, weil ich einen Fehler mache.


1
Funktioniert nicht so, wie Sie es geschrieben haben: GregorianCalendar.setTime () gibt nichts zurück.
f_puras

5

Ich musste einige Änderungen vornehmen, damit es funktioniert, da sich einige Dinge in der Zwischenzeit geändert zu haben scheinen:

  • xjc würde sich beschweren, dass mein Adapter XmlAdapter nicht erweitert
  • Einige bizarre und nicht benötigte Importe wurden eingezogen (org.w3._2001.xmlschema)
  • Die Analysemethoden dürfen natürlich nicht statisch sein, wenn der XmlAdapter erweitert wird

Hier ist ein funktionierendes Beispiel, hoffe, dies hilft (ich verwende JodaTime, aber in diesem Fall würde SimpleDate ausreichen):

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

In der xsd habe ich die oben angegebenen hervorragenden Referenzen befolgt, daher habe ich diese xml-Anmerkung eingefügt:

<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
Ich bin ein Joda Time-Fan geworden, seit ich diese Frage gestellt habe. So viel besser als die Java SE Datums- und Zeitklassen. Genial für den Umgang mit Zeitzonen!
Jim Tough

1

Ich hatte auch solche Kopfschmerzen. Ich habe es beseitigt, indem ich einfach Zeitfelder in meinem POJO als primitiv lange dargestellt habe. Jetzt behandelt die Generierung meines WS-Client-Codes alles korrekt und kein XML-zu-Java-Mist mehr. Und natürlich ist der Umgang mit Millis auf der Java-Seite einfach und schmerzlos. KISS Prinzip rockt!


1

Mit dieser Anpassung können Sie die Standardzuordnung in java.util.Date ändern

<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

Anpassen von Kalender und Datum beim Marshalling

Schritt 1: Bereiten Sie die Jaxb-Bindungs-XML für benutzerdefinierte Eigenschaften vor. In diesem Fall habe ich mich auf Datum und Kalender vorbereitet

<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: Fügen Sie Apache oder verwandten Plugins mit der Option xsd eine benutzerdefinierte Jaxb-Bindungsdatei hinzu, wie unten erwähnt

<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: Schreiben Sie den Code für die CalendarConverter-Klasse

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

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

   <fileDate>2014-09-25</fileDate> - Date class formatted
</xmlHeader>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.