java datetime - jaxb unmarshal timestamp




localdate @xmlschematype (5)

Я не могу заставить JAXB отменять отметку времени в приложении JAX-RS для Resteasy.

Мой класс выглядит так:

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

Есть идеи?

Благодарю.


Answers

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

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

}

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

}

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

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

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


Чтобы заставить XML-маршаллер генерировать xsd: дату, отформатированную как 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>

Я уверен, что это O (n), поскольку память инициализируется при распределении массива. Он не должен быть выше O (n), и я не вижу способа сделать его меньше, чем O (n), поэтому это единственный вариант.

Для дальнейшего развития Java инициализирует массивы при распределении. Нет никакого способа обнулить область памяти, не прогуливаясь по ней, и размер региона диктует количество инструкций. Поэтому нижняя граница O (n). Кроме того, нет смысла использовать алгоритм обнуления медленнее, чем линейный, поскольку существует линейное решение, поэтому верхняя граница должна быть O (n). Поэтому O (n) - единственный ответ, который имеет смысл.

Просто для удовольствия, однако, представьте себе странное аппаратное обеспечение, в котором ОС имеет контроль над мощностью в отдельных областях памяти и может обнулить область, отключив питание и затем включить. Кажется, это будет O (1). Но область может быть настолько большой, пока утилита не исчезнет (не захочет потерять все), поэтому при запросе нулевой области все равно будет O (n) с большим делителем.





java datetime jaxb