2010-03-25 107 views
60

我無法讓JAXB在Resteasy JAX-RS服務器應用程序中解組時間戳。jaxb unmarshal timestamp

我的類看起來是這樣的:

@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; 
     } 
    } 
} 

任何想法?

謝謝。

回答

106

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

我真的想出瞭如何使用@XmlJavaTypeAdapter進行翻譯。有了這個,我已經能夠適應幾個不同的Java類,這些類在我的代碼中需要特殊的處理。謝謝。 – Ralph 2010-07-06 11:01:08

+5

您需要對SimpleDateformat非常小心,因爲它不是線程安全的!我不確定JAXB是否每次都爲適配器創建一個新對象。 – 2011-03-02 04:16:48

+0

欲瞭解更多信息,請參閱:http://bdoughan.blogspot.com/2011/01/jaxb-and-datetime-properties。html – 2011-03-19 01:36:40

10

JAXB無法直接編組Date對象,因爲它們沒有足夠的信息來確定。 JAXB爲此目的引入了XmlGregorianCalendar類,但直接使用它非常不愉快。

我建議將timestamp字段更改爲XmlGregorianCalendar,並在可能的情況下更改各種方法以更新此字段,同時保留您已有的公共接口。

如果你想保持Date領域,那麼你需要實現自己的XmlAdapter類來告訴JAXB您Date如何打開和XML。

+2

JAXB當然可以封裝java.util.Date,只有格式是「yyyy-MM-ddTHH:mm:ss」匹配xsd:dateTime。 EclipseLink JAXB實現(MOXy)也可以處理java.sql.Date/Time/Timestamp類型。 – 2010-07-08 13:27:28

+2

@Blaise:我站在更正 – skaffman 2010-07-08 14:10:15

3

爲了獲取XML編組,以生成一個xsd:日期f ormatted爲YYYY-MM-DD沒有定義我用這種方法建立的javax.xml.datatype.XMLGregorianCalendar中實例的XmlAdapter:

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

使用該適配器應該是線程安全的:

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); 
    } 

} 
+0

我得到了以下錯誤:org.xml.sax.SAXParseException ; lineNumber:0; columnNumber:0; cvc-datatype-valid.1.2.1:'05/10/2017 00:00:00'不是'dateTime'的有效值 – Aguid 2017-10-10 10:01:37

+0

你的字符串'05/10/2017 00:00:00'沒有格式預期:「yyyy-MM-dd'T'HH:mm:ss」 - 您應該更改輸入或格式 – dermoritz 2017-10-10 10:56:28

+0

INFRAXML 2.2:javax.xml.bind.MarshalException - 帶有鏈接的異常: [org.xml.sax。的SAXParseException; lineNumber:0; columnNumber:0; cvc-datatype-valid.1.2.1:'2017-10-10T14:59:34'不是'date'的有效值。] – Aguid 2017-10-10 13:00:12