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;
}
}