JAXB (Jakarta XML Binding) is a popular way to bind XML schemas to Java objects. However, out of the box, JAXB doesn’t support the modern Java 8+ java.time API like LocalDate or LocalDateTime. It still defaults to javax.xml.datatype.XMLGregorianCalendar.

In this post, I’ll show you how to configure JAXB and the jaxb2-maven-plugin to generate Java classes that use java.time.LocalDate and LocalDateTime instead.

The Problem

By default, this schema will generate a field of type XMLGregorianCalendar:

<xs:element name="timestamp" type="xs:dateTime"/>

That’s outdated and clunky in modern Java. Let’s fix that.

Configure the JAXB Plugin

We use the jaxb2-maven-plugin to generate the classes and apply a custom binding file to map xs:dateTime to java.time.LocalDateTime.

Here’s the plugin configuration:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <version>2.5.0</version> <!-- or newer -->
    <executions>
        <execution>
            <id>xjc</id>
            <goals>
                <goal>xjc</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <sources>
            <source>src/main/resources/xsd/events.xsd</source>
        </sources>
        <xjbSources>
            <xjbSource>src/main/resources/xsd/bindings.xjb</xjbSource>
        </xjbSources>
        <packageName>ch.transgourmet.demo.xml.messages</packageName>
        <outputDirectory>${project.build.directory}/generated-sources/jaxb</outputDirectory>
    </configuration>
</plugin>

Custom Bindings for java.time

Create a binding file (bindings.xjb) to tell JAXB to use LocalDateTime and LocalDate, and how to parse/print them.

<jaxb:bindings xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               jaxb:version="3.0">
    <jaxb:globalBindings>
        <jaxb:javaType name="java.time.LocalDateTime"
                       xmlType="xs:dateTime"
                       parseMethod="ch.transgourmet.demo.core.config.LocalDateTimeAdapter.parse"
                       printMethod="ch.transgourmet.demo.core.config.LocalDateTimeAdapter.print"/>
        <jaxb:javaType name="java.time.LocalDate"
                       xmlType="xs:date"
                       parseMethod="ch.transgourmet.demo.core.config.LocalDateAdapter.parse"
                       printMethod="ch.transgourmet.demo.core.config.LocalDateAdapter.print"/>
    </jaxb:globalBindings>
</jaxb:bindings>

Adapter Classes

Now provide static parse/print methods for the adapters. Keep it simple and robust:

LocalDateTimeAdapter

public class LocalDateTimeAdapter {

    public static LocalDateTime parse(String value) {
        return value != null ? LocalDateTime.parse(value) : null;
    }

    public static String print(LocalDateTime value) {
        return value != null ? value.toString() : null;
    }
}

LocalDateAdapter

ublic class LocalDateAdapter {

    public static LocalDate parse(String value) {
        return value != null ? LocalDate.parse(value) : null;
    }

    public static String print(LocalDate value) {
        return value != null ? value.toString() : null;
    }
}

✅ Tip: You can customize the format with DateTimeFormatter if needed.

Result

Now the generated JAXB classes use java.time.LocalDateTime and LocalDate directly. No more legacy date types!

@XmlElement(name = "timestamp", required = true)
protected LocalDateTime timestamp;

Summary

With a simple binding file and some adapter glue code, JAXB becomes compatible with modern Java time APIs — making your code cleaner and your date handling less painful.