====== Mapear directamente una clase local time de JDK 8 en un bean de entidad ======
Con el JDK 8 se introdujo una nueva [[https://www.oracle.com/technetwork/es/articles/java/paquete-java-time-2390472-esa.html|API para gestionar el tiempo]], mucho mas completa que la anterior ([[https://docs.oracle.com/javase/7/docs/api/java/util/Date.html|clase Date]] y [[https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html|clase Calendar]]).
Con esta nueva versión de la API se aumenta la precisión de milisegundos a nanosegundos (En la API anterior esta la clase [[https://docs.oracle.com/javase/7/docs/api/java/sql/Timestamp.html|clase Timestamp]], que permitia la gestión de nanosegundos).
Esta nueva API nos añade principalmente las siguientes clases:
* [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html|LocalDateTime]] que permite gestionar la fecha y la hora hasta los nanosegundos sin zona horaria. Se asume la zona horaria local del sistema.
* [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html|LocalDate]] que permite gestionar la fecha sin zona horaria. Se asume la zona horaria local del sistema.
* [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html|LocalTime]] que permite gestionar la hora hasta los nanosegundos sin zona horaria. Se asume la zona horaria local del sistema.
Para mapear estas nuevas clases directamente en los bean de entidad se han definido los siguientes tipos Hibernate:
* **//LocalDateTimeUserType//**: permite mapear objetos [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html|LocalDateTime]] a tipo //TIMESTAP// o //DATETIME// de SQL.
* **//LocalDateUserType//**: permite mapear objetos [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html|LocalDate]] a tipo //DATE// de SQL.
* **//LocalDateFromTimestampUserType//**: permite mapear objetos [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html|LocalDate]] a tipo //TIMESTAMP// de SQL.
* **//LocalDateUserType//**: permite mapear objetos [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html|LocalDate]] a tipo //DATE// de SQL.
* **//LocalTimeUserType//**: permite mapear objetos [[https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html|LocalTime]] a tipo //TIME// de SQL.
===== Configuración =====
Podes utilizar los anteriores tipos de conversores de Hibernate de dos maneras:
* Utilizando la anotación en la definición de la columna del bean de entidad.
* Utilizando el fichero //package-info.java// para registrar los tipos en el paquete. De esta forma no ahce falta registrarlo en la definición de la columna.
==== Utilizar un Tipo en la Definición de la Columna ====
Veamos varios ejemplos, uno por cada tipo de conversor. Empecemos por el //LocalDateTimeUserType//, que lo hemos registrado en el método //getDateTime()// del bean de entidad //LocalDateTimeUserEntity// con la anotación //@Type( type = LocalDateTimeUserType.TYPE )//.
package es.um.atica.hibernate.type.entities;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
@Entity
@Table( name = "LOCAL_DATE_TIME" )
public class LocalDateTimeUserEntity {
private int id;
private LocalDateTime dateTime; // yyyy-MM-dd hh:mm:ss.nnnnnnnnn
public LocalDateTimeUserEntity() {
}
public LocalDateTimeUserEntity( int id, LocalDateTime dateTime ) {
this.id = id;
this.dateTime = dateTime;
}
@Id
@Column( name = "ID", nullable = false )
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
@Type( type = LocalDateTimeUserType.TYPE )
@Column( name = "LOCAL_DATE_TIME", nullable = false )
public LocalDateTime getDateTime() {
return dateTime;
}
public void setDateTime( LocalDateTime dateTime ) {
this.dateTime = dateTime;
}
@Override
public String toString() {
return "LocalDateTimeUserEntity [id=" + id + ", dateTime=" + dateTime + "]";
}
}
Continuamos por el //LocalDateUserType//, que lo hemos registrado en el método //getDate()// del bean de entidad //LocalDateUserEntity // con la anotación //@Type( type = LocalDateUserType.TYPE )//.
package es.um.atica.hibernate.type.entities;
import java.time.LocalDate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
@Entity
@Table( name = "LOCAL_DATE" )
public class LocalDateUserEntity {
private int id;
private LocalDate date; // yyyy-MM-dd
public LocalDateUserEntity() {
}
public LocalDateUserEntity( int id, LocalDate date ) {
this.id = id;
this.date = date;
}
@Id
@Column( name = "ID", nullable = false )
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
@Type( type = LocalDateUserType.TYPE )
@Column( name = "LOCAL_DATE", nullable = false )
public LocalDate getDate() {
return date;
}
public void setDate( LocalDate date ) {
this.date = date;
}
@Override
public String toString() {
return "LocalTimesUserEntity [id=" + id + ", date=" + date + "]";
}
}
Para terminar, vemos el //LocalTimeUserType//, que lo hemos registrado en el método //getTime()// del bean de entidad //LocalTimeUserEntity // con la anotación //@Type( type = LocalTimeUserType.TYPE )//.
package es.um.atica.hibernate.type.entities;
import java.time.LocalTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
@Entity
@Table( name = "LOCAL_TIME" )
public class LocalTimeUserEntity {
private int id;
private LocalTime time; // hh:mm:ss.nnnnnnnnn
public LocalTimeUserEntity() {
}
public LocalTimeUserEntity( int id, LocalTime time ) {
this.id = id;
this.time = time;
}
@Id
@Column( name = "ID", nullable = false )
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
@Type( type = LocalTimeUserType.TYPE )
@Column( name = "LOCAL_TIME", nullable = false )
public LocalTime getTime() {
return time;
}
public void setTime( LocalTime time ) {
this.time = time;
}
@Override
public String toString() {
return "LocalTimesUserEntity [id=" + id + ", time=" + time + "]";
}
}
==== Utilizar el fichero package-info.java ====
Utilizando el fichero //package-info.java// podemos registrar los tipos de conversor de hibernate para un paquete do código, y ya no haría falta utilizar la anotación //@Type// en la definición de la columna. Veamos un ejemplo con el paquete de código //es.um.atica.hibernate.type.entities//:
@TypeDefs( {
@TypeDef( name = "localDateType", defaultForType = LocalDate.class, typeClass = LocalDateUserType.class ),
@TypeDef( name = "localDateTimeType",
defaultForType = LocalDateTime.class,
typeClass = LocalDateTimeUserType.class ),
@TypeDef( name = "localTimeType", defaultForType = LocalTime.class, typeClass = LocalTimeUserType.class )
} )
package es.um.atica.hibernate.type.entities;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
import es.um.atica.hibernate.type.LocalDateTimeUserType;
import es.um.atica.hibernate.type.LocalDateUserType;
import es.um.atica.hibernate.type.LocalDateFromTimestampUserType;
import es.um.atica.hibernate.type.LocalTimeUserType;
En aplicaciones FundeWeb 1.5 el import de las clases viene del paquete //org.umu.atica.jpa.types//, quedando:
import org.umu.atica.jpa.types.LocalDateTimeUserType;
import org.umu.atica.jpa.types.LocalDateUserType;
import org.umu.atica.jpa.types.LocalDateFromTimestampUserType;
import org.umu.atica.jpa.types.LocalTimeUserType;
Aunque Eclipse deberia de importarlas automaticamente.
Ahora nos queda añadir la siguiente propiedad //packagesToScan// en el fichero //persistence.xml//:
...
...
Ya no es necesario hacer nada más.
===== Bibliografia y Ejemplos =====
* [[https://www.baeldung.com/java-8-date-time-intro|Introduction to the Java 8 Date/Time API]]
* [[https://www.baeldung.com/current-date-time-and-timestamp-in-java-8|Get the Current Date, Time and Timestamp in Java 8]]
* [[https://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html|Java SE 8 Date and Time]]
* [[https://www.oracle.com/technetwork/es/articles/java/paquete-java-time-2390472-esa.html|Paquete java.time de Java 8: Fechas y horas]]
* [[http://blog.eddumelendez.me/2016/07/conociendo-la-nueva-date-api-en-java-8-parte-i/|Conociendo la nueva Date API en Java 8 (Parte I)]]
* [[http://blog.eddumelendez.me/2016/07/conociendo-la-nueva-date-api-en-java-8-parte-ii/|Conociendo la nueva Date API en Java 8 (Parte II)]]
----
--- //[[juanmiguel.bernal@ticarum.es|JUAN MIGUEL BERNAL GONZALEZ]] 30/05/2019 10:43//