Domanda

sto cercando un metodo semplice di conversione tra java.util.Date e javax.xml.datatype.XMLGregorianCalendar in entrambe le direzioni.

Ecco il codice che sto usando ora :

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'è qualcosa di più semplice, come una chiamata API che ho trascurato?

La conversione tra una data XML / tempo standard e una data di oggetto Java sembra un compito abbastanza di routine e sono sorpreso che devo scrivere questo codice a tutti.

Qualche suggerimento?

Note: Le mie classi JAXB vengono generati automaticamente da uno schema. Il processo di generazione sul mio progetto non permette per me fare modifiche manuali alle classi generate. Xs: dateTime elementi vengono generati da XJC come XMLGregorianCalendar nelle classi JAXB. Lo schema viene esteso e ottimizzato periodicamente, così mi è permesso di apportare modifiche limitate al file di schema XSD.

AGGIORNAMENTO SULLA SOLUZIONE: La soluzione proposta da Blaise mi ha permesso di prendere XMLGregorianCalendar fuori dal mix e affrontare java.util.Calendar oggetti invece. Con l'aggiunta di una clausola vincolante JAXB nella parte superiore del mio file di schema, XJC è in grado di generare mappature più appropriate per xs: dateTime nelle mie classi JAXB. Ecco alcuni frammenti che mostrano le modifiche nel mio file XSD.

L'elemento principale nel file 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 vincolante blocco annotazione, inserita immediatamente dopo elemento radice 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>

Dal momento che i xs XML: dateTime campo anche negozi di fuso orario, potrebbe essere meglio per me lavorare con il calendario, invece di Data comunque dato oggetti Calendario avere una buona API per lavorare con i locali e fusi orari. In ogni caso, io sono molto più felice di trattare con gli oggetti Calendario invece di XMLGregorianCalendar. Non c'è bisogno per i metodi di conversione che ho elencato più sopra. Non ho fatto tutta la strada per java.util.Date, ma abbastanza vicino!

È stato utile?

Soluzione

Perché non usare un file esterno vincolante per dire XJC per generare java.util.Date campi invece di XMLGregorianCalendar?

Si veda anche Come posso mappare xs: data da java.util.Date? Blog

Altri suggerimenti

Da XMLGregorianCalendar a java.util.Date si può semplicemente fare:

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

Da java.util.Date a XMLGregorianCalendar si può semplicemente fare:

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

Codice modificato dopo il primo commento di @ f-Puras, per causa faccio un errore.

Ho dovuto fare alcune modifiche per farlo funzionare, come alcune cose sembrano aver cambiato nel frattempo:

  • xjc si lamentava che il mio adattatore non si estende XMLAdapter
  • alcune importazioni bizzarre e inutili sono stati elaborati in (org.w3._2001.xmlschema)
  • metodi parsing non devono essere statiche quando si estende il XMLAdapter, ovviamente

Ecco un esempio di lavoro, speriamo che questo aiuta (sto usando JodaTime ma in questo caso SimpleDate sarebbe sufficiente):

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

Nel XSD, ho seguito le ottime referenze di cui sopra, così ho incluso questo xml annotazione:

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

Anche io ha avuto questo tipo di mal di testa. Sono liberato di esso semplicemente rappresentare campi di tempo come primitivo lungo nel mio POJO. Ora la generazione di mio cliente WS maniglia codice tutto correttamente e non più stronzate XML-to-Java. E, naturalmente, si tratta di Millis sul lato Java è semplice e indolore. principio KISS rocce!

È possibile utilizzare l'questa personalizzazione per modificare il mapping predefinito per 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>

Personalizzazione del calendario e la data mentre Marshalling

Passaggio 1: Preparare JAXB xml vincolante per le proprietà personalizzate, in questo caso ho preparato per la data e calendario

<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: file di collegamento Add JAXB personalizzato per Apache o alcun plugin correlate al opzione XSD come accennato seguente

<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: scrivere il codice per la classe 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: uscita

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

   <fileDate>2014-09-25</fileDate> - Date class formatted
</xmlHeader>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top