временная метка jaxb unmarshal - PullRequest
60 голосов
/ 26 марта 2010

Я не могу заставить 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 ]

107 голосов
/ 06 июля 2010

JAXB может обрабатывать класс java.util.Date. Однако он ожидает формат:

«гггг-ММ-дд'ТЧЧ: мм: сс» вместо «гггг-ММ-дд ЧЧ: мм: сс»

Если вы хотите использовать этот формат даты, я бы предложил использовать 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);
    }

}

Затем вы должны указать этот адаптер в свойстве отметки времени:

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

}
11 голосов
/ 26 марта 2010

JAXB не может маршалировать Date объекты напрямую, потому что у них недостаточно информации, чтобы быть однозначным. JAXB ввел класс XmlGregorianCalendar для этой цели, но использовать его очень неприятно.

Я предлагаю изменить ваше поле timestamp на XmlGregorianCalendar и изменить различные методы для обновления этого поля, сохранив, по возможности, уже открытый публичный интерфейс.

Если вы хотите сохранить поле Date, вам нужно реализовать свой собственный класс XmlAdapter, чтобы сообщить JAXB, как превратить ваш Date в и из XML.

3 голосов
/ 13 мая 2015

Использование этого адаптера должно быть безопасным для потоков:

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

}
3 голосов
/ 30 апреля 2014

Чтобы маршаллер XML сгенерировал xsd: date в формате YYYY-MM-DD без определения 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));
}

В результате я инициализировал поле 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>
...