Question

Je suis à la recherche d'une méthode simple de conversion entre java.util.Date et javax.xml.datatype.XMLGregorianCalendar dans les deux sens.

Voici le code que j'utilise maintenant :

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

Y at-il plus simple, comme un appel API que j'ai oublié?

Conversion entre une date XML standard / heure et un objet date Java semble être une tâche assez de routine et je suis surpris que je dois écrire ce code du tout.

Toutes les suggestions?

NOTES: Mes classes JAXB sont générées automatiquement à partir d'un schéma. Le processus de construction de mon projet ne permet pas pour moi de faire des modifications manuelles aux classes générées. Les éléments xs: dateTime sont générés par XJC comme XMLGregorianCalendar dans les classes de JAXB. Le schéma est étendu et peaufiné périodiquement, donc je suis autorisé à apporter des modifications limitées au fichier XSD de schéma.

MISE À JOUR SUR LA SOLUTION: La solution proposée par Blaise m'a permis de prendre XMLGregorianCalendar hors du mélange et concernent les objets java.util.Calendar à la place. En ajoutant une clause contraignante JAXB en haut de mon dossier de schéma, XJC est capable de générer plus de correspondances appropriées pour xs: dateTime dans mes classes JAXB. Voici quelques extraits qui montrent les modifications dans mon fichier XSD.

L'élément racine dans le fichier 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">

bloc de liaison annotation JAXB, inséré immédiatement après l'élément racine dans 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>

Depuis le XML xs: dateTime champ fuseau horaire aussi des magasins, il pourrait être préférable pour moi de travailler avec le calendrier au lieu de date de toute façon puisque les objets de calendrier ont une assez bonne API pour travailler avec les lieux et les fuseaux horaires. Dans tous les cas, je suis beaucoup plus heureux de traiter avec des objets de calendrier au lieu de XMLGregorianCalendar. Pas besoin de méthodes de conversion que j'énumérés ci-dessus plus. Je n'ai pas tout le chemin à java.util.Date, mais assez proche!

Était-ce utile?

La solution

Pourquoi ne pas utiliser un fichier de liaison externe pour dire XJC pour générer java.util.Date champs au lieu de XMLGregorianCalendar?

Voir aussi Comment puis-je la carte xs: date java.util.Date? Blog

Autres conseils

De XMLGregorianCalendar à java.util.Date vous pouvez simplement faire:

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

De java.util.Date à XMLGregorianCalendar vous pouvez simplement faire:

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 modifié après le premier commentaire de @ f-puras, par parce que je fais une erreur.

Je devais faire quelques changements pour le faire fonctionner, car certaines choses semblent avoir changé dans l'intervalle:

  • xjc se plaindrait que mon adaptateur ne couvre pas XMLAdapter
  • certaines importations bizarres et inutiles ont été établis dans (org.w3._2001.xmlschema)
  • les méthodes d'analyse syntaxique ne doivent pas être statiques lors de l'extension du XMLAdapter, évidemment

Voici un exemple de travail, espérons que cette aide (j'utilise JodaTime mais dans ce cas SimpleDate serait suffisant):

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

Dans le xsd, j'ai suivi les excellentes références données ci-dessus, donc j'ai inclus cette annotation 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>

Moi aussi eu ce genre de maux de tête. Est débarrassé de cela par un simple représentant les champs de temps comme primitive longue dans mon POJO. Maintenant, la génération de mon code client WS poignée tout correctement et pas plus de merde XML à Java. Et bien sûr, avec le traitement Millis du côté Java est simple et indolore. roches principe KISS!

Vous pouvez utiliser la cette personnalisation pour modifier le mappage par défaut à 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>

Personnalisation du calendrier et de la date en Marshaling

Étape 1: Préparer JAXB lier xml pour des propriétés personnalisées, Dans ce cas, je me préparais pour la date et le calendrier

<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: fichier de liaison Ajouter JAXB personnalisé à Apache ou tout plugins associés à l'option xsd comme mentionné ci-dessous

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

Cons 3: écrire le code pour 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: Sortie

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

   <fileDate>2014-09-25</fileDate> - Date class formatted
</xmlHeader>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top