J2SE has become sole large that its different parts don't play well.
That is pitty but nothing to do. There is probably a lack of resources in Oracle to fill gaps.
So, to the point.
There is relatively new API to work with time defined in: package java.time. There is older API JAXB to serialize and deserialize beans to and from XML (and often to JSON). To JAXB viable, it should be able to deal with basic primitive types. The problem is that JAXB does not handle LocalDate, LocalTime, LocalDateTime, and ZonedDateTime out of the box.
We do understand that:
But this does not help, and we should define/redefine serialization adapters using some drop in code or third party libraries. Here are these convenience adapters:
LocalDateAdapter.java import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZonedDateTime; import javax.xml.bind.annotation.adapters.XmlAdapter; /** * An adapter for the bean properties of {@link LocalDate} type. */ public class LocalDateAdapter extends XmlAdapter<String, LocalDate> { /** * Converts {@link LocalDate} into a string value. * @param value a value to convert. Can be null. * @return a string value. */ @Override public String marshal(LocalDate value) throws Exception { return value == null ? null : value.toString(); } /** * Converts a string value into a {@link LocalDate} * instance. * @param value a value to convert. Can be null. * @return a {@link LocalDate} instance. */ @Override public LocalDate unmarshal(String value) throws Exception { if (value == null) { return null; } int p = value.indexOf('T'); if (p < 0) { return LocalDate.parse(value); } while(++p < value.length()) { switch(value.charAt(p)) { case '+': case '-': case 'Z': { return ZonedDateTime.parse(value).toLocalDate(); } } } return LocalDateTime.parse(value).toLocalDate(); } } LocalDateTimeAdapter.java import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZonedDateTime; import javax.xml.bind.annotation.adapters.XmlAdapter; /** * An adapter for the bean properties of {@link LocalDateTime} type. */ public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> { /** * Converts {@link LocalDateTime} into a string value. * @param value a value to convert. Can be null. * @return a string value. */ @Override public String marshal(LocalDateTime value) throws Exception { return value == null ? null : value.toString(); } /** * Converts a string value into a {@link LocalDateTime} instance. * @param value a value to convert. Can be null. * @return a {@link LocalDateTime} instance. */ @Override public LocalDateTime unmarshal(String value) throws Exception { if (value == null) { return null; } int p = value.indexOf('T'); if (p < 0) { return LocalDateTime.of(LocalDate.parse(value), LocalTime.MIN); } while(++p < value.length()) { switch(value.charAt(p)) { case '+': case '-': case 'Z': { return ZonedDateTime.parse(value).toLocalDateTime(); } } } return LocalDateTime.parse(value); } } LocalTimeAdapter.java import java.time.LocalDate;import java.time.LocalTime; import javax.xml.bind.annotation.adapters.XmlAdapter; /** * An adapter for the bean properties of {@link LocalTime} type. */ public class LocalTimeAdapter extends XmlAdapter<String, LocalTime> { /** * Converts {@link LocalTime} into string value. * @param value a value to convert. Can be null. * @return a string value */ @Override public String marshal(LocalTime value) throws Exception { return value == null ? null : value.toString(); } /** * Converts a string value into a {@link LocalTime} instance. * @param value a value to convert. Can be null. * @return a {@link LocalTime} instance. */ @Override public LocalTime unmarshal(String value) throws Exception { return value == null ? null : LocalTime.parse(value); } }
LocalDateAdapter.java
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZonedDateTime; import javax.xml.bind.annotation.adapters.XmlAdapter; /** * An adapter for the bean properties of {@link LocalDate} type. */ public class LocalDateAdapter extends XmlAdapter<String, LocalDate> { /** * Converts {@link LocalDate} into a string value. * @param value a value to convert. Can be null. * @return a string value. */ @Override public String marshal(LocalDate value) throws Exception { return value == null ? null : value.toString(); } /** * Converts a string value into a {@link LocalDate} * instance. * @param value a value to convert. Can be null. * @return a {@link LocalDate} instance. */ @Override public LocalDate unmarshal(String value) throws Exception { if (value == null) { return null; } int p = value.indexOf('T'); if (p < 0) { return LocalDate.parse(value); } while(++p < value.length()) { switch(value.charAt(p)) { case '+': case '-': case 'Z': { return ZonedDateTime.parse(value).toLocalDate(); } } } return LocalDateTime.parse(value).toLocalDate(); } }
LocalDateTimeAdapter.java
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZonedDateTime; import javax.xml.bind.annotation.adapters.XmlAdapter; /** * An adapter for the bean properties of {@link LocalDateTime} type. */ public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> { /** * Converts {@link LocalDateTime} into a string value. * @param value a value to convert. Can be null. * @return a string value. */ @Override public String marshal(LocalDateTime value) throws Exception { return value == null ? null : value.toString(); } /** * Converts a string value into a {@link LocalDateTime} instance. * @param value a value to convert. Can be null. * @return a {@link LocalDateTime} instance. */ @Override public LocalDateTime unmarshal(String value) throws Exception { if (value == null) { return null; } int p = value.indexOf('T'); if (p < 0) { return LocalDateTime.of(LocalDate.parse(value), LocalTime.MIN); } while(++p < value.length()) { switch(value.charAt(p)) { case '+': case '-': case 'Z': { return ZonedDateTime.parse(value).toLocalDateTime(); } } } return LocalDateTime.parse(value); } }
LocalTimeAdapter.java
import java.time.LocalDate;import java.time.LocalTime; import javax.xml.bind.annotation.adapters.XmlAdapter; /** * An adapter for the bean properties of {@link LocalTime} type. */ public class LocalTimeAdapter extends XmlAdapter<String, LocalTime> { /** * Converts {@link LocalTime} into string value. * @param value a value to convert. Can be null. * @return a string value */ @Override public String marshal(LocalTime value) throws Exception { return value == null ? null : value.toString(); } /** * Converts a string value into a {@link LocalTime} instance. * @param value a value to convert. Can be null. * @return a {@link LocalTime} instance. */ @Override public LocalTime unmarshal(String value) throws Exception { return value == null ? null : LocalTime.parse(value); } }
To make them work either field/properties or package should be annotated with JAXB xml adapters.
The simplest way is to annotate it on package level like this:
package-info.java @XmlJavaTypeAdapters( { @XmlJavaTypeAdapter(value = LocalDateAdapter.class, type = LocalDate.class), @XmlJavaTypeAdapter(value = LocalTimeAdapter.class, type = LocalTime.class), @XmlJavaTypeAdapter(value = LocalDateTimeAdapter.class, type = LocalDateTime.class) }) package com.nesterovskyBros.demo.entities; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
package-info.java
@XmlJavaTypeAdapters( { @XmlJavaTypeAdapter(value = LocalDateAdapter.class, type = LocalDate.class), @XmlJavaTypeAdapter(value = LocalTimeAdapter.class, type = LocalTime.class), @XmlJavaTypeAdapter(value = LocalDateTimeAdapter.class, type = LocalDateTime.class) }) package com.nesterovskyBros.demo.entities; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;