Pregunta

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

Este es 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 de XML / hora estándar y una fecha objeto de Java parece una tarea bastante rutinario y me sorprende que tengo que escribir el código en absoluto.

¿Alguna sugerencia?

Notas: Mis clases JAXB son generados automáticamente a partir de un esquema. El proceso de construcción de mi proyecto no permite para mí hacer cambios manuales en las clases generadas. Los xs: elementos dateTime están siendo generados por XJC como XMLGregorianCalendar en las clases JAXB. El esquema se extiende y ajustado periódicamente, por lo que me permite hacer cambios limitados en el archivo de esquema XSD.

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. Mediante la adición de una cláusula vinculante JAXB en la parte superior de mi archivo de esquema, XJC es capaz de generar asignaciones más apropiadas para xs: dateTime en mis clases JAXB. Éstos son 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 los xs: dateTime XML campo también tiendas de zona horaria, tal vez sería mejor para mí trabajar con el calendario en lugar de la fecha de todos modos ya que los objetos tienen un calendario API bastante bueno para trabajar con lugares y zonas horarias. En cualquier caso, estoy mucho más feliz para hacer frente a los objetos del calendario en lugar de XMLGregorianCalendar. No hay necesidad de que los métodos de conversión que se enumeran más arriba más. No he tenido todo el camino a java.util.Date, pero lo suficientemente cerca!

¿Fue útil?

Solución

¿Por qué no utiliza un archivo de enlace externo a decir XJC para generar java.util.Date campos en lugar de XMLGregorianCalendar?

También vea ¿Cómo puedo asignar xs: fecha para java.util.Date? Blog

Otros consejos

De XMLGregorianCalendar a java.util.Date sólo tiene que hacer:

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

De java.util.Date a XMLGregorianCalendar sólo tiene que 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 hago un error.

he tenido que hacer algunos cambios para hacer que funcione, ya que parecen haber cambiado entretanto algunas cosas:

  • xjc se quejaba de que mi adaptador no se extiende XmlAdapter
  • algunas importaciones extrañas y que no sean necesarios se dibuja en (org.w3._2001.xmlschema)
  • los métodos de análisis sintáctico no deben ser estática cuando se extiende la XmlAdapter, obviamente

Este es un ejemplo de trabajo, 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 he incluido esta anotación 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>

Yo también tenía este tipo de dolor de cabeza. Se deshizo de ello simplemente que representa los campos de tiempo como primitiva tiempo en mi POJO. Ahora la generación de mi cliente WS mango código todo correctamente y sin basura más de XML a Java. Y, por supuesto, se trata de Millis en el lado de Java es simple y sin dolor. principio KISS rocas!

Puede utilizar la esta personalización para cambiar la asignación predeterminada a 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>

Personalizar el calendario y la fecha mientras Marshaling

Paso 1: Preparar jaxb xml de unión para las propiedades personalizadas, en este caso i preparado para 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: Agregar archivo de enlace a medida jaxb a Apache o algún complemento relacionados a 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 la clase 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: salida

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

   <fileDate>2014-09-25</fileDate> - Date class formatted
</xmlHeader>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top