localdatetime java8 hibernate date java-8

hibernate - java8 - localdatetime jpa spring boot



Java 8 LocalDateTime e Hibernate 4 (4)

Tengo el siguiente fragmento de descripción de clase:

... @Column(name = "invalidate_token_date") @Temporal(TemporalType.TIMESTAMP) private LocalDateTime invalidateTokenDate; ....

Este código no funciona porque @Temporal no admite LocalDateTime. Vi la sugerencia de cómo usar LocalDateTime de Joda-Time pero uso Java 8.

Por favor, dame un consejo.


PD
Aquí está mi dependencia actual de JPA:

<dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> </dependency>


Creé un complemento simple para permitirnos usar clases java.time. *. En este momento se implementan las clases más utilizadas. Echa un vistazo aquí: https://github.com/garcia-jj/jpa-javatime .

Si está utilizando Maven, esta es la configuración del artefacto:

<dependency> <groupId>br.com.otavio</groupId> <artifactId>jpa-javatime</artifactId> <version>0.2</version> </dependency>

Hay más información sobre cómo usar en la página del proyecto.

Gracias.


Dado que Hibernate no lo admite, debe implementar un tipo de usuario como se muestra en this ejemplo.

import org.hibernate.HibernateException; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.type.StandardBasicTypes; import org.hibernate.usertype.EnhancedUserType; import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; public class LocalDateTimeUserType implements EnhancedUserType, Serializable { private static final int[] SQL_TYPES = new int[]{Types.TIMESTAMP}; @Override public int[] sqlTypes() { return SQL_TYPES; } @Override public Class returnedClass() { return LocalDateTime.class; } @Override public boolean equals(Object x, Object y) throws HibernateException { if (x == y) { return true; } if (x == null || y == null) { return false; } LocalDateTime dtx = (LocalDateTime) x; LocalDateTime dty = (LocalDateTime) y; return dtx.equals(dty); } @Override public int hashCode(Object object) throws HibernateException { return object.hashCode(); } @Override public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { Object timestamp = StandardBasicTypes.TIMESTAMP.nullSafeGet(resultSet, names, session, owner); if (timestamp == null) { return null; } Date ts = (Date) timestamp; Instant instant = Instant.ofEpochMilli(ts.getTime()); return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); } @Override public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if (value == null) { StandardBasicTypes.TIMESTAMP.nullSafeSet(preparedStatement, null, index, session); } else { LocalDateTime ldt = ((LocalDateTime) value); Instant instant = ldt.atZone(ZoneId.systemDefault()).toInstant(); Date timestamp = Date.from(instant); StandardBasicTypes.TIMESTAMP.nullSafeSet(preparedStatement, timestamp, index, session); } } @Override public Object deepCopy(Object value) throws HibernateException { return value; } @Override public boolean isMutable() { return false; } @Override public Serializable disassemble(Object value) throws HibernateException { return (Serializable) value; } @Override public Object assemble(Serializable cached, Object value) throws HibernateException { return cached; } @Override public Object replace(Object original, Object target, Object owner) throws HibernateException { return original; } @Override public String objectToSQLString(Object object) { throw new UnsupportedOperationException(); } @Override public String toXMLString(Object object) { return object.toString(); } @Override public Object fromXMLString(String string) { return LocalDateTime.parse(string); } }

El nuevo usertype se puede usar en la asignación con la anotación @Type. Por ej.

@Type(type="com.hibernate.samples.type.LocalDateTimeUserType") @Column(name = "invalidate_token_date") private LocalDateTime invalidateTokenDate;

La anotación @Type necesita una ruta completa a la clase que implementa la interfaz userType; Esta es la fábrica para producir el tipo de destino de la columna asignada.

Here''s explica cómo hacer lo mismo en JPA2.1


Para cualquier usuario de Hibernate 5.x, hay

<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-java8</artifactId> <version>5.0.0.Final</version> </dependency>

No necesitas hacer nada más. Simplemente agregue la dependencia, y los tipos de tiempo de Java 8 deberían funcionar como cualquier otro tipo básico, no se requieren anotaciones.

private LocalDateTime invalidateTokenDate;

Nota: sin embargo, esto no se guardará en el tipo de timestamp de timestamp . Al probar con MySQL, se guarda en el tipo de datetime y datetime .


Si puede usar Java EE 7, hay una solution más elegante:

>> Implemente esto:

@Converter(autoApply = true) public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Date> { @Override public Date convertToDatabaseColumn(LocalDateTime date) { if (date == null){ return null; } return date.toDate(); } @Override public LocalDateTime convertToEntityAttribute(Date value) { if (value == null) { return null; } return LocalDateTime.fromDateFields(value); } }

>> Use así:

... @Column(name = "invalidate_token_date") private LocalDateTime invalidateTokenDate; ....

El valor (autoApply = true) significa que @Converter se usa automáticamente para la conversión de cada propiedad LocalDateTime en su entidad JPA.

Por cierto, AttributeConverter es bastante bueno para mapear Enums.