Marshalling LocalDate using JAXB

Viewed 24492

I'm building a series of linked classes whose instances I want to be able to marshall to XML so I can save them to a file and read them in again later.

At present I'm using the following code as a test case:

import javax.xml.bind.annotation.*;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import java.time.LocalDate;

public class LocalDateExample
{
  @XmlRootElement
  private static class WrapperTest {
    public LocalDate startDate;
  }

  public static void main(String[] args) throws JAXBException
  {
    WrapperTest wt = new WrapperTest();
    LocalDate ld = LocalDate.of(2016, 3, 1);
    wt.startDate = ld;
    marshall(wt);
  }

  public static void marshall(Object jaxbObject) throws JAXBException
  {
    JAXBContext context = JAXBContext.newInstance(jaxbObject.getClass());
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    marshaller.marshal(jaxbObject, System.out);
  }
}

The XML output is:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wrapperTest>
    <startDate/>
</wrapperTest>

Is there a reason why the startDate element is empty? I would like it to contain the string representation of the date (i.e. toString()). Do I need to write some code of my own in order to do this?

The output of java -version is:

openjdk version "1.8.0_66-internal"
OpenJDK Runtime Environment (build 1.8.0_66-internal-b17)
OpenJDK 64-Bit Server VM (build 25.66-b17, mixed mode)
3 Answers

As Nikolay Antipov mentioned in this commment there is already a well-tested threeten library that provides 14 type adapters (as of 2021-04-26) where one of them is the:

LocalDateXmlAdapter

and can be used e.g. like this on some Java field (generally not recommended by me though):

@XmlJavaTypeAdapter(value = LocalDateXmlAdapter.class) myLocalDt;

Instead I would recommend the package-info.java approach to do it implicitly in each package on the package level so it is applied automagically to e.g. all fields of the LocalDate type in all package classes:

  • create a file named src/java/my/xmlconv/classes/package-info.java

  • its content:

    @XmlJavaTypeAdapters({
      @XmlJavaTypeAdapter(value=LocalDateTimeXmlAdapter.class, type=LocalDateTime.class)
    })
    package my.xmlconv.classes;
    
    import java.time.LocalDateTime;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
    import io.github.threetenjaxb.core.LocalDateTimeXmlAdapter;
    
Related