One of the core addition of Java 8 is the Date Time API. As most of you probably know, Java has been missing a consistent approach for Date and Time. This approach solves some of the common issues issues with java.util.Date and java.sql.Date messy classes. In this tutorial we will learn how to use LocalDate and LocalDateTime classes to map JPA Entity classes.
LocalDate
LocalDate is an immutable class that represents Date with default format of yyyy-MM-dd. In its simplest form, you can use now() method to get the current date but of course you can provide arguments for year, month and date to create LocalDate instance. Let’s look at a simple example:
//Current Date LocalDate today = LocalDate.now(); System.out.println("Current Date="+today); //LocalDate with input arguments LocalDate xmas = LocalDate.of(2016, Month.DECEMBER, 25); System.out.println("XMas 2016="+xmas);
LocalDateTime
LocalDateTime is an immutable date-time object that represents a date-time, with default format as yyyy-MM-dd-HH-mm-ss.zzz. You can think of it of an equivalent of a Timestamp. It provides a factory method that takes LocalDate and LocalTime input arguments to create LocalDateTime instance. The above examples, using a LocalDateTime, can be rewritten as:
//Current Date LocalDateTime today = LocalDateTime.now(); System.out.println("Current Date="+today); //LocalDateTime with input arguments LocalDateTime xmas = LocalDateTime.of(2016, Month.DECEMBER, 25,12, 30,0); System.out.println("XMas 2016 at 12:30:00 ="+xmas);
Using LocalDate and LocalDateTime with JPA
That being said, can we use the java.time API with JPA? With the current JPA 2.1 specification there is no direct support for the java.time API. However, you can use an javax.persistence.AttributeConverter to automate the conversion between the old Date formats and the new java.time API.
Let’s take the SimpleProperty class from our Demo JavaEE7Project:
package com.mastertheboss.model; import java.time.LocalDate; import java.time.LocalDateTime; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class SimpleProperty { @Id @Column(name="id") private String key; private String value; private LocalDateTime timestamp; private LocalDate date; // Getter/Setters }
And here’s the Converter class which will automatically convert the LocalDate object to java.sql.Date and viceversa:
package com.mastertheboss.converter; import javax.persistence.AttributeConverter; import javax.persistence.Converter; @SuppressWarnings("UnusedDeclaration") @Converter(autoApply = true) public class LocalDateConverter implements AttributeConverter<java.time.LocalDate, java.sql.Date> { @Override public java.sql.Date convertToDatabaseColumn(java.time.LocalDate attribute) { return attribute == null ? null : java.sql.Date.valueOf(attribute); } @Override public java.time.LocalDate convertToEntityAttribute(java.sql.Date dbData) { return dbData == null ? null : dbData.toLocalDate(); } }
As we are also using a LocalDateTime field, we will add a converter also for this type:
package com.mastertheboss.converter; import javax.persistence.AttributeConverter; import javax.persistence.Converter; @Converter(autoApply = true) public class LocalDateTimeConverter implements AttributeConverter<java.time.LocalDateTime, java.sql.Timestamp> { @Override public java.sql.Timestamp convertToDatabaseColumn(java.time.LocalDateTime attribute) { return attribute == null ? null : java.sql.Timestamp.valueOf(attribute); } @Override public java.time.LocalDateTime convertToEntityAttribute(java.sql.Timestamp dbData) { return dbData == null ? null : dbData.toLocalDateTime(); } }
Our ServiceBean class will record the LocalDate and LocalDateTime at the time the Entity is inserted.
package com.mastertheboss.ejb; import java.time.LocalDate; import java.time.LocalDateTime; import javax.ejb.Stateless; import javax.enterprise.event.Event; import javax.inject.Inject; import javax.persistence.EntityManager; import javax.persistence.Query; import com.mastertheboss.model.SimpleProperty; @Stateless public class ServiceBean { @Inject private Event<SimpleProperty> propEventSrc; @Inject private EntityManager em; public void put(SimpleProperty p) { // Set LocalDateTime and LocalDate LocalDateTime time = LocalDateTime.now(); LocalDate date = LocalDate.now(); p.setDate(date); p.setTimestamp(time); em.persist(p); propEventSrc.fire(p); } public void delete(SimpleProperty p) { Query query = em.createQuery("delete FROM SimpleProperty p where p.key='" + p.getKey() + "'"); query.executeUpdate(); propEventSrc.fire(p); } }
The full source of this project is available at: https://github.com/fmarchioni/mastertheboss/tree/master/javaee/javaee7examplelocal
Build, deploy and test it!