我无法让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;
}
}
}
有什么想法吗?
感谢。
答案 0 :(得分:107)
JAXB可以处理java.util.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;
}
}
答案 1 :(得分:11)
JAXB无法直接封送Date
个对象,因为它们没有足够的信息来明确。为此目的,JAXB引入了XmlGregorianCalendar
类,但直接使用它是非常不愉快的。
我建议将您的timestamp
字段更改为XmlGregorianCalendar
,并更改您的各种方法以更新此字段,同时保留您已有的公共界面。
如果您想保留Date
字段,那么您需要实现自己的XmlAdapter
类,告诉JAXB如何将Date
转换为XML格式。
答案 2 :(得分:3)
为了让XML marshaller生成格式化为YYYY-MM-DD的xsd:date而不定义XmlAdapter,我使用此方法构建了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));
}
结果我初始化了JAXB编译器生成的类的XMLGregorianCalendar字段(在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>
答案 3 :(得分:3)
使用此适配器应该是线程安全的:
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);
}
}