Using LocalDate and LocalDateTime with JPA

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!

JPA Localdate tutorial