Conversion simple entre java.util.Date et XMLGregorianCalendar

Je cherche 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 a-t-il quelque chose de plus simple, comme un appel API que j’ai oublié?

La conversion entre une date / heure XML standard et un object date Java semble être une tâche assez courante et je suis surpris de devoir écrire ce code.

Aucune suggestion?

REMARQUES: Mes classes JAXB sont générées automatiquement à partir d’un schéma. Le processus de construction de mon projet ne me permet pas de modifier manuellement les classes générées. Les éléments xs: dateTime sont générés par XJC en tant que XMLGregorianCalendar dans les classes JAXB. Le schéma est étendu et modifié périodiquement, donc je suis autorisé à apporter des modifications limitées au fichier XSD du schéma.

MISE À JOUR SUR LA SOLUTION: La solution proposée par Blaise m’a permis de supprimer XMLGregorianCalendar et de traiter les objects java.util.Calendar à la place. En ajoutant une clause de liaison JAXB en haut de mon fichier de schéma, XJC peut générer des mappages plus appropriés pour xs: dateTime dans mes classes JAXB. Voici quelques extraits qui montrent les modifications dans mon fichier XSD.

L’élément racine du fichier XSD:

  

Bloc d’annotation de liaison JAXB, inséré immédiatement après l’élément racine dans XSD:

        

Étant donné que le champ XML xs: dateTime stocke également le fuseau horaire, il peut être préférable de travailler avec Calendar au lieu de Date car les objects Calendar disposent d’une assez bonne API pour travailler avec les parameters régionaux et les fuseaux horaires. Dans tous les cas, je suis beaucoup plus heureux de traiter des objects de calendrier au lieu de XMLGregorianCalendar. Pas besoin des méthodes de conversion que j’ai énumérées plus haut. Je n’ai pas eu tout le chemin pour java.util.Date, mais assez proche!

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

Voir aussi Comment puis-je mapper xs: date à java.util.Date? Blog

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

J’ai dû apporter quelques modifications pour que cela fonctionne, car certaines choses semblent avoir changé entre-temps:

  • xjc se plaindrait que mon adaptateur n’étende pas XmlAdapter
  • des importations bizarres et inutiles ont été tirées (org.w3._2001.xmlschema)
  • les méthodes d’parsing ne doivent pas être statiques lors de l’extension de XmlAdapter, évidemment

Voici un exemple pratique, j’espère que cela vous aidera (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 { @Override public Object marshal(Object dt) throws Exception { return new DateTime((Date) dt).toSsortingng("YYYY-MM-dd"); } @Override public Object unmarshal(Object s) throws Exception { return DatatypeConverter.parseDate((Ssortingng) s).getTime(); } } 

Dans le xsd, j’ai suivi les excellentes références données ci-dessus, j’ai donc inclus cette annotation xml:

         

Moi aussi j’ai eu ce genre de mal de tête. On s’en débarrasse simplement en représentant les champs de temps comme primitifs longs dans mon POJO. Maintenant, la génération de mon code client WS gère tout correctement, sans plus de corruption XML-to-Java. Et bien sûr, le traitement du millis côté Java est simple et sans douleur. Principe KISS roches!

Vous pouvez utiliser cette personnalisation pour changer le mappage par défaut en java.util.Date

       

Personnalisation du calendrier et de la date lors du marshaling

Étape 1: Préparez jaxb binding XML pour les propriétés personnalisées, dans ce cas, j’ai préparé pour la date et le calendrier

      

Setp 2: Ajouter un fichier de liaison jaxb personnalisé à Apache ou à tout autre plug-in associé à l’option xsd comme mentionné ci-dessous

  ${project.basedir}/src/main/resources/tutorial/xsd/yourxsdfile.xsd com.tutorial.xml.packagename ${project.basedir}/src/main/resources/xsd/jaxbbindings.xml  

Setp 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 Ssortingng 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 Ssortingng printDate(java.util.Date val) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); return simpleDateFormat.format(val); } } 

Setp 4: Sortie

   2014-09-25T07:23:05 Calendar class formatted 2014-09-25 - Date class formatted