Using the new Java8 date / time classes with Hibernate

At the time of writing – January 2015 – neither JPA2.1 nor the actual Hibernate implementation 4.3.8.FINAL support the use of the new Java8 date and time classes as properties for an entity class. But JPA2.1 has a @Converter annotation that together with the AttributeConverter interface enables a simple solution to the problem.

(Update July 10, 2015): Hibernate 5.0.0 – currently RC2 – supports the new types without any further need for Converters; hibernate-java8 is needed on the classpath. Thanks to Paul Paulsson for the information)

I show the conversion using the java.time.LocalDate class in my entity which is converted to a java.sql.Date class to be used by Hibernate.

First we need to write a Converter implementation, I called it LocalDateConverter:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Date;
import java.time.LocalDate;

/**
 * Converter to convert from java.time.LocalDate to java.sql.Date and back.
 *
 * @author P.J.Meisch (pj.meisch@sothawo.com)
 */
@Converter
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate localDate) {
        return null == localDate ? null : Date.valueOf(localDate);
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
        return null == date ? null : date.toLocalDate();
    }
}

In the database, I have a PERSON table which besides things like names has a column named DATEOFBIRTH which is of type DATE.

This is mapped to an Entity class Person (i omit everything but the relevant part). By annotating the getter for the property with the @Convert annotation, the conversion is automatically applied when writing or reading the property to the database.

Update: When Hibernate shall create the table according to the entity, the annotation must be written at the field, not at the getter.

/**
 * Person entity.
 *
 * @author P.J.Meisch (pj.meisch@sothawo.com)
 */
@Entity
@Table(name = "person")
public class Person implements Serializable {

    private LocalDate dateOfBirth;

    @Column(name = "dateofbirth")
    @Convert(converter = LocalDateConverter.class)
    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }
}

Converters for the other time classes are as easily written.

Update:

If your entity has more than one field of the given type, or more than one entities have properties of this type, you can define the Converter to autoApply:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Date;
import java.time.LocalDate;

/**
 * Converter to convert from java.time.LocalDate to java.sql.Date and back.
 *
 * @author P.J.Meisch (pj.meisch@sothawo.com)
 */
@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate localDate) {
        return null == localDate ? null : Date.valueOf(localDate);
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
        return null == date ? null : date.toLocalDate();
    }
}

You then don’t need to specify the converter for the different properties, they are converted automatically:

/**
 * Person entity.
 *
 * @author P.J.Meisch (pj.meisch@sothawo.com)
 */
@Entity
@Table(name = "person")
public class Person implements Serializable {

    private LocalDate dateOfBirth;
    private LocalDate dateOfDeatch;

    @Column(name = "dateofbirth")
    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

    @Column(name = "dateofdeath")
    public LocalDate getDateOfDeath() {
        return dateOfDeath;
    }

    public void setDateOfDeath(LocalDate dateOfDeath) {
        this.dateOfDeath = dateOfDeath;
    }
}