【问题标题】:How to persist JSR 310 java.time.LocalDateTime in JPA with Hibernate using usertype如何使用用户类型在 JPA 中使用 Hibernate 持久化 JSR 310 java.time.LocalDateTime
【发布时间】:2014-07-12 07:08:37
【问题描述】:

我正在尝试使用用户类型在 JPA 中使用 Hibernate 将 java.time.LocalDateTime 持久化到 Java 8 中。

我有一个属性注释如下。

@Type(type = "org.jadira.usertype.dateandtime.threetenbp.PersistentLocalDateTime")
private java.time.LocalDateTime createdDateTime;

我已经为用户类型添加了如下依赖项。

compile 'org.jadira.usertype:usertype.extended:3.2.0.GA'
compile 'org.threeten:threetenbp:0.9'

但是,我遇到了以下异常

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1225)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:119)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:853)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843)
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:397)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842)
    at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:152)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:336)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
    ... 20 more
Caused by: org.hibernate.MappingException: Unable to instantiate custom type: org.jadira.usertype.dateandtime.threetenbp.PersistentLocalDateTime
    at org.hibernate.type.TypeFactory.custom(TypeFactory.java:218)
    at org.hibernate.type.TypeFactory.custom(TypeFactory.java:204)
    at org.hibernate.type.TypeFactory.byClass(TypeFactory.java:103)
    at org.hibernate.type.TypeResolver.heuristicType(TypeResolver.java:130)
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:327)
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:310)
    at org.hibernate.mapping.Property.isValid(Property.java:241)
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:496)
    at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1358)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1849)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
    ... 28 more
Caused by: java.lang.TypeNotPresentException: Type org.threeten.bp.LocalDateTime not present
    at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:117)
    at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125)
    at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
    at sun.reflect.generics.visitor.Reifier.reifyTypeArguments(Reifier.java:68)
    at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:138)
    at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
    at sun.reflect.generics.repository.ClassRepository.getSuperclass(ClassRepository.java:86)
    at java.lang.Class.getGenericSuperclass(Class.java:764)
    at org.jadira.usertype.spi.utils.reflection.TypeHelper.getTypeArguments(TypeHelper.java:73)
    at org.jadira.usertype.spi.shared.AbstractSingleColumnUserType.<init>(AbstractSingleColumnUserType.java:41)
    at org.jadira.usertype.spi.shared.AbstractParameterizedUserType.<init>(AbstractParameterizedUserType.java:24)
    at org.jadira.usertype.dateandtime.threetenbp.PersistentLocalDateTime.<init>(PersistentLocalDateTime.java:34)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
    at java.lang.Class.newInstance(Class.java:433)
    at org.hibernate.type.TypeFactory.custom(TypeFactory.java:213)
    ... 39 more
Caused by: java.lang.ClassNotFoundException: org.threeten.bp.LocalDateTime
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:340)
    at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114)
    ... 56 more

堆栈跟踪暗示ClassNotFound,但我添加了依赖'org.threeten:threetenbp:0.9'

我的问题

如何使用用户类型在 JPA 中使用 Hibernate 持久化 java.time.LocalDateTime

【问题讨论】:

  • 尝试运行 mvn dependency:tree 并检查您的依赖层次结构中是否有多个版本的threetenbp。
  • 结果。尽管我尝试下载了很多次,但我没有获得threetenbp 依赖项。现在工作。 :)

标签: java hibernate jpa usertype java-time


【解决方案1】:

它不起作用,因为您使用了错误的类型。对于 JSR-310 类,您应该使用 org.jadira.usertype.dateandtime.threeten.PersistentLocalDateTime 而不是 org.jadira.usertype.dateandtime.threetenbp.PersistentLocalDateTime
您不需要 org.threeten:threetenbp:0.9 依赖项。

【讨论】:

    【解决方案2】:

    恢复一个旧线程,但由于它没有答案,这里有一个建议。 由于 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);
        }
    
    }
    

    【讨论】:

    猜你喜欢
    • 2015-06-13
    • 2013-11-12
    • 2010-09-24
    • 2016-02-20
    • 1970-01-01
    • 2015-05-26
    • 2014-07-06
    • 1970-01-01
    • 2017-04-09
    相关资源
    最近更新 更多