2015-01-02 90 views
15

我有下面的类描述片段:的Java 8 LocalDateTime和Hibernate 4

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

此代码不会因为@Temporal工作不支持LocalDateTime.我看到的建议如何使用LocalDateTime乔达 - 时间,但我使用Java 8.

请指教我一些东西。


P.S.
这是我目前的JPA依赖:

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

回答

19

因为Hibernate不支持它,你需要实现如图this例如,用户类型。

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

} 

新的usertype然后可以用@Type注释映射。对于例如

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

@Type注释需要实现userType接口的类的完整路径;这是生成映射列的目标类型的工厂。

Here's如何做同样的事情在JPA2.1

+0

而我应该如何改变映射后添加你的答案? – gstackoverflow

+0

更新了使用信息的答案 –

+0

请注意,如果将其转换为存储'java.util.LocalDate'字段,则不能通过'java.sql.Date.toInstant()'方法去执行,因为会抛出异常;使用'toLocalDate'来代替。 – Gwaptiva

9

如果你可以使用Java EE 7,有更优雅solution

>>实现此:

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

> >像这样使用:

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

Value (autoApply = true)表示@Converter自动用于转换JPA实体中的每个LocalDateTime属性。

Btw,AttributeConverter对映射Enums来说也不错。

+0

哪个库为您提供localDateTime toDate和fromDateFields方法? – obesechicken13

+0

在这里找到了一个转换器:http://stackoverflow.com/questions/19431234/converting-between-java-time-localdatetime-and-java-util-date – obesechicken13

+1

它实际上是一个JPA特性,它也适用于Spring Data JPA,不仅仅是Java EE。 –

0

我创建了一个简单的插件,允许我们使用java.time。*类。目前最常用的类是实现的。看看这里:https://github.com/garcia-jj/jpa-javatime

如果您正在使用Maven,这是神器配置:

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

还有更多的信息,如何在项目页面使用。

谢谢。

35

对于任何Hibernate的5.x的用户,有

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

您不需要做任何事情。只需添加依赖关系,Java 8时间类型应该像任何其他基本类型一样工作,不需要注释。

private LocalDateTime invalidateTokenDate; 

注意:这不会保存到timestamp类型。使用MySQL进行测试,它保存为datetime类型。

+1

保存了我的夜晚:)谢谢 –

+0

这对于弹簧配置还不够。在添加hibernate-java8依赖项后仍然会发生ClassCastException异常。 –

+1

谢谢。在Spring 4.2.5和Hibernate 5.1.31中添加hibernate-java8工件。正在获取org.hibernate.type.SerializationException:无法对具有LocalDateTime字段的实体进行反序列化。 –

相关问题