convert java xml generics jaxb

java - convert - xmlgregoriancalendar c#



JAXB Bindings File Establece el tipo @XmlElement en String en lugar de XMLGregorianCalendar (2)

ACTUALIZAR

resumiendo:

  1. tiene un esquema que usa el estilo de fecha en algún lugar y no puede cambiar el esquema
  2. tiene algunos datos XML que utilizan ese esquema y especifica alguna fecha con zona horaria (por lo tanto, es el formato yyyy-MM-ddXXX )
  3. desea eliminar la parte XXX de la representación de la fecha en ese archivo (la fecha en sí no se envía en ninguna zona horaria, la fecha es solo un número)

así que esto podría ser un esquema de muestra:

<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <element name="foo"> <complexType> <sequence> <element name="bar" type="date" minOccurs="1" maxOccurs="1"/> </sequence> </complexType> </element> </schema>

Esto podría ser una muestra de datos:

<?xml version="1.0" encoding="UTF-8"?> <foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="foo.xsd"> <bar>2014-01-01+06:00</bar> </foo>

esta es la clase anotada JAXB

@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Foo implements Serializable { private static final long serialVersionUID = 1L; @XmlElement(name = "bar") @XmlJavaTypeAdapter(DateAdapter.class) @XmlSchemaType(name = "date") private Date bar; // getters/setters }

esto es adaptador de fecha

public class DateAdapter extends XmlAdapter<String, Date> { @Override public String marshal(Date date) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); df.setTimeZone(TimeZone.getTimeZone("GMT")); return df.format(date); } @Override public Date unmarshal(String date) throws ParseException { DateFormat df = new SimpleDateFormat("yyyy-MM-ddXXX"); return df.parse(date); } }

Este es el principal, validando contra el esquema:

public static void main(String[] args) throws JAXBException, SAXException { JAXBContext context = JAXBContext.newInstance(Foo.class); SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = sf.newSchema(Foo.class.getResource("/foo.xsd")); Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.setSchema(schema); Foo foo = (Foo) unmarshaller.unmarshal(Foo.class.getResource("/foo.xml")); System.out.println("unmarshalled: " + foo.getBar()); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "foo.xsd"); marshaller.setSchema(schema); marshaller.marshal(foo, System.out); }

y esta es la salida, la zona horaria se ha eliminado y la representación de la fecha ha cambiado obviamente

unmarshalled: Tue Dec 31 19:00:00 CET 2013 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="foo.xsd"> <bar>2013-12-31</bar> </foo>

tal vez este cambio en la representación de la fecha no sea lo que usted esperaría, pero esto no es un problema de JAXB, la fecha representada no ha cambiado.

Estaba olvidando los enlaces para revertir generar Foo:

<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0"> <jaxb:globalBindings> <xjc:javaType name="java.util.Date" xmlType="xsd:date" adapter="aaa.DateAdapter" /> </jaxb:globalBindings> </jaxb:bindings>

FIN DE ACTUALIZACIÓN

lo siento, demasiado tiempo para un comentario ...

no puedo entender

  1. ¿Por qué demonios estás usando XmlGregorianCalendar ?
  2. ¿Por qué debería unmarshal / unmarshal ( serialize / deserialize ) la misma estructura de datos?
  3. ¿Por qué debería eliminar la zona horaria?

y

  1. Yo uso java.util.Date directo y simple
  2. marshal / unmarshal siempre debe incluir String s (al menos para XML)
  3. Realmente no veo una buena razón para eliminar arbitrariamente una parte de una representación de fecha. Tal vez quieras serializarlo de una manera absoluta.

sin embargo

public class DateAdapter extends XmlAdapter<String, Date> { @Override public String marshal(Date date) { DateFormat df = DateFormat.getDateTimeInstance(); df.setTimeZone(TimeZone.getTimeZone("GMT")); return df.format(date); } @Override public Date unmarshal(String date) throws ParseException { DateFormat df = DateFormat.getDateTimeInstance(); df.setTimeZone(TimeZone.getTimeZone("GMT")); return df.parse(date); } public static void main(String[] args) throws ParseException { DateAdapter adapter = new DateAdapter(); String str = adapter.marshal(new Date()); System.out.println(str); // 16-dic-2013 10.02.09 --> to gmt Date date = adapter.unmarshal(str); System.out.println(date); // Mon Dec 16 11:02:09 CET 2013 --> correct, i''m gmt+1 } }

Estoy intentando crear un XmlAdapter que toma un XMLGregorianCalendar y genera un XMLGregorianCalendar . El propósito es simplemente eliminar los datos de la zona horaria del elemento cuando se desasignan datos.

Se parece a esto:

public class TimezoneRemoverAdapter extends XmlAdapter<XMLGregorianCalendar, XMLGregorianCalendar> { public XMLGregorianCalendar unmarshal(XMLGregorianCalendar xgc) { if(xgc == null) { return null; } xgc.setTimezone(DatatypeConstants.FIELD_UNDEFINED); return xgc; } public XMLGregorianCalendar marshal(XMLGregorianCalendar xgc) { return xgc; } }

Esto funciona bien para el siguiente código:

public class FooElement { @XmlElement(name="bar-date") @XmlJavaTypeAdapter(TimezoneRemoverAdapter.class) @XmlSchemaType(name = "date") protected XMLGregorianCalendar barDate; }

Desafortunadamente, cuando genero el código usando un archivo jaxb-bindings.xml , el código anterior se ve así:

public class FooElement { @XmlElement(name="bar-date", type=java.lang.String.class) @XmlJavaTypeAdapter(TimezoneRemoverAdapter.class) @XmlSchemaType(name = "date") protected XMLGregorianCalendar barDate; }

Establece el tipo en String , por lo que mi método anterior no funciona. La configuración de tipo String está anulando el tipo XMLGregorianCalendar que debería ser. Puedo cambiarlo manualmente, pero prefiero no tener que acordarme de actualizarlo cada vez que se regeneren los archivos jaxb. ¿Alguien sabe si hay una opción para configurar manualmente el tipo @XmlElement o lo ha ignorado?

Aquí está la parte relevante del archivo jaxb-bindings.xml :

<jxb:bindings node=".//xs:element[@name=bar-date]"> <jxb:property> <jxb:baseType> <jxb:javaType name="javax.xml.datatype.XMLGregorianCalendar" adapter="foo.bar.TimezoneRemoverAdapter" /> </jxb:baseType> </jxb:property> </jxb:bindings>


Tienes que especificar el tipo de java de manera diferente, en tu caso:

<jxb:javaType name="javax.xml.datatype.XMLGregorianCalendar" xmlType="xs:date" printMethod="foo.bar.TimezoneRemoverAdapter.marshall" parseMethod="foo.bar.TimezoneRemoverAdapter.unmarshall" />

Funciona bien para mí e hice algo similar con más adaptadores:

<jaxb:globalBindings> <xjc:serializable uid="12343" /> <jaxb:javaType name="java.util.Date" xmlType="xs:date" printMethod="com.foo.DateAdapter.printDate" parseMethod="com.foo.DateAdapter.parseDate" /> <jaxb:javaType name="java.util.Date" xmlType="xs:dateTime" printMethod="com.foo.DateAdapter.printDate" parseMethod="com.foo.DateAdapter.parseDate" /> <jaxb:javaType name="java.util.Date" xmlType="xs:time" printMethod="com.foo.TimeAdapter.printTime" parseMethod="com.foo.TimeAdapter.parseTime" /> </jaxb:globalBindings>

globalBindings enlaces anteriores como un globalBindings en un archivo diferente con la extensión .xjb y lo uso en cualquier lugar donde lo necesite.