JAXB unmarshal timestamp
Я не могу заставить JAXB отменить отметку времени в серверном приложении Resteasy JAX-RS.
мой класс выглядит так:
@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;
}
}
}
какие идеи?
спасибо.
4 ответа:
JAXB может обрабатывать java.утиль.класс Date. Однако он ожидает формат:
"yyyy-MM-dd'T'HH: mm:ss" вместо "yyyy-MM-dd HH:mm:ss"
Если вы хотите использовать этот формат даты, я бы предложил использовать XmlAdapter, это будет выглядеть примерно так:
import java.text.SimpleDateFormat; import java.util.Date; import javax.xml.bind.annotation.adapters.XmlAdapter; public class DateAdapter extends XmlAdapter<String, Date> { 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); } }
затем вы должны указать этот адаптер в свойстве timestamp:
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 не может маршал
Date
объекты напрямую, потому что у них недостаточно информации, чтобы быть однозначными. JAXB не представилXmlGregorianCalendar
класс для этой цели, но это очень неприятно использовать напрямую.Я предлагаю изменить ваш
timestamp
поле должно бытьXmlGregorianCalendar
, и измените свои различные методы, чтобы обновить это поле, сохраняя при этом открытый интерфейс, который у вас уже есть, где это возможно.если вы хотите сохранить
чтобы заставить XML-маршаллер генерировать xsd: date в формате YYYY-MM-DD без определения XmlAdapter, я использовал этот метод для создания экземпляра javax.XML.тип данных.XMLGregorianCalendar:
public XMLGregorianCalendar buildXmlDate(Date date) throws DatatypeConfigurationException { return date==null ? null : DatatypeFactory.newInstance().newXMLGregorianCalendar(new SimpleDateFormat("yyyy-MM-dd").format(date)); }
в результате я инициализировал поле XMLGregorianCalendar класса, созданного компилятором JAXB (в 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);
и получил тег в формате, как ожидалось:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <REPORT> ... <MY_DATE>2014-04-30</MY_DATE> ... </REPORT>
использование этого адаптера должно быть потокобезопасным:
public class DateXmlAdapter extends XmlAdapter<String, Date> { /** * Thread safe {@link DateFormat}. */ private static final ThreadLocal<DateFormat> DATE_FORMAT_TL = new ThreadLocal<DateFormat>() { @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); } }