jaxb unmarshal timestamp

No puedo hacer que JAXB marque una marca de tiempo en una aplicación de servidor Resteasy JAX-RS.

Mi clase se ve así:

@XmlAccessorType(XmlAccessType.NONE) @XmlRootElement(name = "foo") public final class Foo { // Other fields omitted @XmlElement(name = "timestamp", required = true) protected Date timestamp; public Foo() {} public Date getTimestamp() { return timestamp; } public String getTimestampAsString() { return (timestamp != null) ? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp) : null; } public void setTimestamp(final Date timestamp) { this.timestamp = timestamp; } public void setTimestamp(final String timestampAsString) { try { this.timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(timestampAsString); } catch (ParseException ex) { this.timestamp = null; } } } 

¿Algunas ideas?

Gracias.

JAXB puede manejar la clase java.util.Date. Sin embargo, espera el formato:

“aaaa-MM-dd’T’HH: mm: ss” en lugar de “aaaa-MM-dd HH: mm: ss”

Si desea usar ese formato de fecha, le sugiero que use un XmlAdapter, se vería como el siguiente:

 import java.text.SimpleDateFormat; import java.util.Date; import javax.xml.bind.annotation.adapters.XmlAdapter; public class DateAdapter extends XmlAdapter { private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public String marshal(Date v) throws Exception { return dateFormat.format(v); } @Override public Date unmarshal(String v) throws Exception { return dateFormat.parse(v); } } 

Luego, debe especificar este adaptador en su propiedad de marca de tiempo:

 import java.util.Date; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @XmlAccessorType(XmlAccessType.NONE) @XmlRootElement(name = "foo") public final class Foo { // Other fields omitted @XmlElement(name = "timestamp", required = true) @XmlJavaTypeAdapter(DateAdapter.class) protected Date timestamp; public Foo() {} public Date getTimestamp() { return timestamp; } public void setTimestamp(final Date timestamp) { this.timestamp = timestamp; } } 

JAXB no puede ordenar objetos de Date directamente, porque no tienen suficiente información para ser inequívocos. JAXB introdujo la clase XmlGregorianCalendar para este propósito, pero es muy desagradable de usar directamente.

XmlGregorianCalendar cambiar su campo de timestamp para que sea un XmlGregorianCalendar , y cambie sus diversos métodos para actualizar este campo mientras conserva la interfaz pública que ya tiene, siempre que sea posible.

Si desea mantener el campo Date , deberá implementar su propia clase XmlAdapter para decirle a JAXB cómo convertir su Date XmlAdapter desde XML.

Para que el marshaller XML genere una xsd: fecha formateada como YYYY-MM-DD sin definir un XmlAdapter, utilicé este método para crear una instancia de javax.xml.datatype.XMLGregorianCalendar:

 public XMLGregorianCalendar buildXmlDate(Date date) throws DatatypeConfigurationException { return date==null ? null : DatatypeFactory.newInstance().newXMLGregorianCalendar(new SimpleDateFormat("yyyy-MM-dd").format(date)); } 

Con el resultado inicié el campo XMLGregorianCalendar de la clase generada por el comstackdor JAXB (en Eclipse):

  Date now = new Date(); ... report.setMYDATE(buildXmlDateTime(now)); ... JAXBContext context = JAXBContext.newInstance(ReportType.class); Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.marshal(new ObjectFactory().createREPORT(report), writer); 

Y obtuve la etiqueta formateada como se esperaba:

   ... 2014-04-30 ...  

El uso de este adaptador debe ser seguro para subprocesos:

 public class DateXmlAdapter extends XmlAdapter { /** * Thread safe {@link DateFormat}. */ private static final ThreadLocal DATE_FORMAT_TL = new ThreadLocal() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); } }; @Override public Date unmarshal(String v) throws Exception { return DATE_FORMAT_TL.get().parse(v); } @Override public String marshal(Date v) throws Exception { return DATE_FORMAT_TL.get().format(v); } }