Автор оригинала: Catalin Burcea.
1. Введение
В этом учебнике мы увидим, как разграничить объекты даты с различными форматами с помощью JAXB .
Во-первых, мы покроем формат даты по умолчанию. Затем мы изумим, как использовать различные форматы. Мы также увидим, как мы можем справиться с общей проблемой, которая возникает с этими методами.
2. Схема привязки Java
Во-первых, нам необходимо понять взаимосвязь между типами XML Schema и Java- . В частности, мы заинтересованы в отображении между объектами XML Schema и Java-дата.
Согласно Схема для отображения java , Есть три типа данных Schema, которые мы должны принять во внимание: xsd:дата , xsd:время и xsd:dateTime . Как мы видим, все они нанесены на карту Javax.xml.datatype.XMLGregorianCalendar .
Мы также должны понять форматы по умолчанию для этих типов XML Schema. xsd:дата и xsd:время типы данных имеют ” YYYY-MM-DD” и ” hh:mm:ss” Форматы. xsd:dateTime формат “ YYYY-MM-DDThh:mm:ss” где ” T” является сепаратором, указывающим начало раздела времени.
3. Использование формата даты шемы по умолчанию
Мы собираемся создать пример, который разграничит объекты даты. Давайте сосредоточимся на xsd:dateTime тип данных, потому что это суперсет других типов.
Давайте использовать простой файл XML, который описывает книгу:
Book1 1979-10-21T03:31:12
Мы хотим сопоставить файл с соответствующими Java- Книжный объект:
@XmlRootElement(name = "book") public class Book { @XmlElement(name = "title", required = true) private String title; @XmlElement(name = "published", required = true) private XMLGregorianCalendar published; @Override public String toString() { return "[title: " + title + "; published: " + published.toString() + "]"; } }
Наконец, нам необходимо создать клиентское приложение, которое преобразует данные XML в java-объекты, полученные jaxB:
public static Book unmarshalDates(InputStream inputFile) throws JAXBException { JAXBContext jaxbContext = JAXBContext.newInstance(Book.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); return (Book) jaxbUnmarshaller.unmarshal(inputFile); }
В вышеуказаном коде мы определили JAXBContext которая является точкой входа в API JAXB. Затем мы использовали JAXB- Унмаршаллер на входной поток для того, чтобы прочитать наш объект:
Если мы забудем вышеуказанный код и напечатаем результат, мы получим следующее Книжный объект:
[title: Book1; published: 1979-11-28T02:31:32]
Следует отметить, что, несмотря на то, что отображение по умолчанию для xsd:dateTime является XMLGregorianCalendar , мы могли бы также использовать более распространенные типы Java: java.util.Date и java.util.Calendar , в соответствии с Руководство для пользователей JAXB .
4. Использование пользовательского формата даты
Приведенный выше пример работает, потому что мы используем формат даты схемы по умолчанию, “YYYY-MM-DDThh:mm:ss”.
Но что, если мы хотим использовать другой формат, как “YYYY-MM-DD hh:mm:ss”, избавиться от “Т” разделитель? Если мы заменим делимитр космическим символом в нашем файле XML, то unmarshalling по умолчанию потерпит неудачу.
4.1. Строительство пользовательского XmlAdapter
Для того, чтобы использовать другой формат даты, мы должны определить XmlАдаптер .
Давайте также посмотрим, как сопоставить xsd:dateTime введать в java.util.Date объект с нашим пользовательским XmlАдаптер:
public class DateAdapter extends XmlAdapter{ private static final String CUSTOM_FORMAT_STRING = "yyyy-MM-dd HH:mm:ss"; @Override public String marshal(Date v) { return new SimpleDateFormat(CUSTOM_FORMAT_STRING).format(v); } @Override public Date unmarshal(String v) throws ParseException { return new SimpleDateFormat(CUSTOM_FORMAT_STRING).parse(v); } }
В этом адаптере мы использовали ПростойdateФормат чтобы отформатировать нашу дату. Мы должны быть осторожны, как ПростойdateФормат не поток-безопасный . Чтобы избежать проблем с несколькими потоками с общим ПростойdateФормат объект, мы создаем новый каждый раз, когда мы в ней нуждается.
4.2. Внутренние данные XmlAdapter
Как видим, XmlAdapter имеет два параметра типа , в данном случае, Струнные и Дата . Первый тип используется внутри XML и называется типом значения. В этом случае JAXB знает, как преобразовать значение XML в Струнные . Второй называется связанным типом и относится к значению в нашем Java-объекте.
Цель адаптера состоит в том, чтобы преобразовать между типом значения и связанным типом, таким образом, что JAXB не может сделать по умолчанию.
Для того, чтобы построить пользовательский Xml Адаптер , мы должны переопределить два метода: XmlAdapter.marshal() и XmlAdapter.unmarshal() .
Во время unmarshalling обязательная структура JAXB сначала анмаршала представление XML на Струнные а затем вызывает DateAdapter.unmarshal() адаптировать тип значения к Дата . Во время маршаллинга обязательная структура JAXB вызывает ДатаАдаптер.маршал () адаптировать Дата Струнные , который затем marshaled к представлению XML.
4.3. Интеграция через аннотации JAXB
ДатаАдаптер работает как плагин для JAXB, и мы собираемся прикрепить его к нашей дате поле с помощью @XmlJavaTypeAdapter аннотация. @XmlJavaTypeAdapte r аннотация определяет использование XmlAdapter для пользовательских unmarshalling :
@XmlRootElement(name = "book") public class BookDateAdapter { // same as before @XmlElement(name = "published", required = true) @XmlJavaTypeAdapter(DateAdapter.class) private Date published; // same as before }
Мы также используем стандартные аннотации JAXB : @XmlRootElement и @XmlElement Аннотации.
Наконец, давайте забудем новый код:
[title: Book1; published: Wed Nov 28 02:31:32 EET 1979]
5. Даты unmarshalling в Java 8
Java 8 представила новую Дата/время API . Здесь мы сосредоточимся на Местное время класс, который является одним из наиболее часто используемых.
5.1. Строительство локальногоdateTime на основе XmlAdapter
По умолчанию JAXB не может автоматически связывать xsd:dateTime значение для Местное время объекта независимо от формата даты. Для преобразования значения даты XML Schema в или из Местное время объект, мы должны определить другую XmlAdapter похож на предыдущий:
public class LocalDateTimeAdapter extends XmlAdapter{ private DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override public String marshal(LocalDateTime dateTime) { return dateTime.format(dateFormat); } @Override public LocalDateTime unmarshal(String dateTime) { return LocalDateTime.parse(dateTime, dateFormat); } }
В этом случае мы использовали ДатаTimeФорматер вместо ПростойdateФормат . Первый был представлен на Java 8 и совместим с новым Дата/время API.
Обратите внимание, что операции преобразования могут делиться ДатаTimeФорматер объект, потому ДатаTimeФорматер является поток-безопасной.
5.2. Интеграция нового адаптера
Теперь давайте заменим старый адаптер на новый в нашем Книжный класса, а также Дата с Местное время :
@XmlRootElement(name = "book") public class BookLocalDateTimeAdapter { // same as before @XmlElement(name = "published", required = true) @XmlJavaTypeAdapter(LocalDateTimeAdapter.class) private LocalDateTime published; // same as before }
Если мы забудем вышеуказанный код, мы получим выход:
[title: Book1; published: 1979-11-28T02:31:32]
Обратите внимание, что LocalDateTime.toString () добавляет “Т” делимитер между датой и временем.
6. Заключение
В этом учебнике мы исследовали даты unmarshalling с использованием JAXB .
Во-первых, мы рассмотрели карту типа XML Schema to Java и создали пример с использованием формата даты XML Schema по умолчанию.
Затем мы узнали, как использовать пользовательский формат даты на основе пользовательского XmlAdapter и увидел, как справиться с безопасностью потока ПростойdateФормат .
Наконец, мы использовали превосходный, безопасный для потоков API Java 8 Date/Time и неустойкие даты с пользовательскими форматами.
Как всегда, исходный код, используемый в учебнике, доступен более на GitHub .