2010-09-09 29 views
106

Estoy buscando un método simple de conversión entre java.util.Date y javax.xml.datatype.XMLGregorianCalendar en ambas direcciones.Conversión simple entre java.util.Date y XMLGregorianCalendar

Aquí está el código que estoy usando ahora:

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

¿Hay algo más simple, como una llamada a la API que he pasado por alto?

La conversión entre una fecha/hora XML estándar y un objeto de fecha Java parece una tarea bastante rutinaria y me sorprende que tenga que escribir este código.

¿Alguna sugerencia?

NOTAS: Mis clases JAXB se autogeneran desde un esquema. El proceso de compilación en mi proyecto no me permite hacer cambios manuales en las clases generadas. XJC está generando los elementos xs: dateTime como XMLGregorianCalendar en las clases de JAXB. El esquema se amplía y modifica periódicamente, por lo que puedo realizar cambios limitados en el archivo XSD del esquema.

ACTUALIZACIÓN EN SOLUCIÓN: La solución propuesta por Blaise me ha permitido tomar XMLGregorianCalendar fuera de la mezcla y hacer frente a java.util.Calendar objetos en su lugar. Al agregar una cláusula de enlace JAXB en la parte superior de mi archivo de esquema, XJC puede generar asignaciones más apropiadas para xs: dateTime en mis clases JAXB. Aquí hay algunos fragmentos que muestran las modificaciones en mi archivo XSD.

El elemento raíz en el archivo 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 unión bloque de anotación, se inserta inmediatamente después de elemento raíz en 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> 

Desde xs XML: campo DateTime también almacena la zona horaria, podría ser mejor para mí trabajar con Calendar en lugar de Date, ya que los objetos Calendar tienen una API bastante buena para trabajar con configuraciones regionales y zonas horarias. En cualquier caso, estoy mucho más contento de lidiar con objetos de Calendar en lugar de XMLGregorianCalendar. Ya no es necesario que los métodos de conversión que mencioné anteriormente. No llegué a java.util.Date, pero lo suficientemente cerca!

+0

Una especie de asidero, pero ¿por qué tienes que ocuparte de objetos XMLGregorianCalendar en primer lugar? Son un poco irritantes. Si provienen de jaxb, es posible usar @XMLTypeAdapter para enlazar directamente con java.util.Date. Por supuesto, si está autogenerando fuera de un esquema, cambiar los objetos puede ser tan irritante cuando se regenera. – Affe

+0

@Affe Estoy autogenerando fuera de un esquema, así que no puedo hacer ningún cambio manual en las clases JAXB generadas –

+0

¿Es esto lo mismo que http://stackoverflow.com/questions/835889/java-util-date-to -xmlgregoriancalendar? –

Respuesta

44

¿Por qué no utilizar un archivo de enlace externo para decirle a XJC que genere campos java.util.Date en lugar de XMLGregorianCalendar?

Véase también: - http://weblogs.java.net/blog/kohsuke/archive/2006/03/how_do_i_map_xs.html

+0

Analizaré esto. Gracias. –

+0

No hay problema. JAXB puede manejar el tipo java.util.Date, solo necesita generarlo en su modelo. Que puede ser complicado –

+0

Eso funcionó para mí. Consulte las ediciones de mi pregunta anterior para obtener detalles sobre lo que hice. –

5

que tenía que hacer algunos cambios para hacer que funcione, ya que algunas cosas parecen haber cambiado desde entonces:

  • xjc se quejaba de que mi adaptador no lo hace extienda XmlAdapter
  • se extrajeron algunas importaciones extrañas e innecesarias (org.w3._2001.xmlschema)
  • los métodos de análisis no debe ser estática cuando se amplía el XmlAdapter, obviamente

es un ejemplo de trabajo aquí, espero que esta ayuda (estoy usando JodaTime pero en este caso SimpleDate sería suficiente):

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

En el xsd, he seguido las excelentes referencias dadas anteriormente, por lo que han incluido esta xml anotación:

<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

Me he convertido en un Fan de Joda Time en el tiempo desde que hice esta pregunta. Mucho mejor que las clases de fecha y hora de Java SE. ¡Impresionante para manejar zonas horarias! –

1

Yo también tuve este tipo de dolor de cabeza. Me deshice de él simplemente representando campos de tiempo como primitivo largo en mi POJO. Ahora la generación de mi código de cliente de WS maneja todo correctamente y no más basura de XML a Java. Y, por supuesto, tratar con millis en el lado de Java es simple e indolora. KISS principio rocas!

79

De XMLGregorianCalendar a java.util.Date simplemente puede hacer:

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

Gracias ... Estaba buscando una forma de convertir XMLGregorianCalendar a tiempo en millis. – Andez

6

De java.util.Date a XMLGregorianCalendar puede simplemente hacer:

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

Código editado después de que el primer comentario de @f-puras, por causa que cometo un error.

+1

No funciona de la forma en que lo escribió: GregorianCalendar.setTime() no devolverá nada. –

0

Personalización del calendario y la fecha, mientras que el cálculo de referencias

Paso 1: Preparar jaxb xml vinculante para las propiedades personalizadas, en este caso he preparado para la fecha y el 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" /> 


Consigna 2 : Agregue el archivo de enlace jaxb personalizado a Apache o cualquier complemento relacionado en la opción xsd como se menciona a continuación

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

Consigna 3: escribir el código para CalendarConverter clase

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

Consigna 4: Salida

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

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

Puede utilizar la esta personalización para cambiar la asignación predeterminada de Java. util.Fecha

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

Cuestiones relacionadas