【问题标题】:ClassCastException Proxy36 cannot be cast to SessionImplementor after Hibernate/Spring 4 upgrade在 Hibernate/Spring 4 升级后,ClassCastException Proxy36 无法转换为 SessionImplementor
【发布时间】:2016-08-13 20:55:10
【问题描述】:

编辑:我不是在问 什么 ClassCastException 是。我在问是什么导致它在 Spring 4/Hibernate 4 的这个特定配置下的 DetachedCriteria 中。

我正在尝试将一些旧代码升级到 Spring 4/Hibernate 4,但我碰壁了,因为 Google 的出现并不多。

我正在尝试在一个非常简单的 Hibernate 存储库上运行 JUnit 测试,但它失败了

java.lang.ClassCastException: com.sun.proxy.$Proxy36 cannot be cast to org.hibernate.engine.spi.SessionImplementor
    at org.hibernate.criterion.DetachedCriteria.getExecutableCriteria(DetachedCriteria.java:84)
    at com.my.app.rest.domain.repository.AbstractHibernateRepository$6.doInHibernate(AbstractHibernateRepository.java:163)
...

这发生在 Hibernate 的 org.hibernate.criterion.DetachedCriteria 类中:

/**
 * Get an executable instance of Criteria to actually run the query.
 *
 * @param session The session to associate the built Criteria with
 *
 * @return The "executable" Criteria
 */
public Criteria getExecutableCriteria(Session session) {
    impl.setSession( (SessionImplementor) session );
    return impl;
}

当它尝试设置 Session(尝试将其转换为 SessionImplementor)时,它会抛出 ClassCastException。

我怀疑这可能是 AOP 问题,但不知道从哪里开始。

我正在使用 Spring 4.3.2.RELEASE 和 Hibernate 4.3.5.Final

休眠上下文.xml:

    <bean id="xxxSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

        <property name="dataSource" ref="xxxDataSource" />

        <property name="mappingResources">
            <list>
                <value>hibernate/xxxUploadDocResponseInfo.hbm.xml</value>
            </list>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${xxx.hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${xxx.hibernate.showsql}</prop>
                <prop key="hibernate.hbm2ddl.auto">${xxx.hibernate.hbm2ddl}</prop>
                <prop key="format_sql">${xxx.hibernate.formatsql}</prop>
                <prop key="hibernate.query.substitutions">true 1, false 0</prop>

            </props>
        </property>
    <alias name="xxxSessionFactory" alias="sessionFactory" />
</bean>

事务上下文.xml:

<bean id="xxxTransactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice id="xxxTxAdvice" transaction-manager="xxxDatasourceTransactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" />
        <!-- all methods begin with save have the transaction -->
        <tx:method name="save*" propagation="REQUIRED"/>
        <tx:method name="add*" propagation="REQUIRED"/>
        <tx:method name="update*" propagation="REQUIRED"/>
        <tx:method name="remove*" propagation="REQUIRED"/>
        <tx:method name="inactivate*" propagation="REQUIRED"/>
        <tx:method name="complete*" propagation="REQUIRED"/>
        <tx:method name="reset*" propagation="REQUIRED"/>
        <tx:method name="get*" read-only="true"/>
        <tx:method name="flag*" read-only="true"/>
        <tx:method name="doWork*" propagation="REQUIRES_NEW" />
    </tx:attributes>
</tx:advice>

<bean id="xxxDatasourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <constructor-arg ref="xxxDataSource" />
</bean>

<aop:config>
    <aop:pointcut id="allBusiness" expression="execution(public * com.blah.xxx.rest.business.*Business.*(..))"/>
    <aop:advisor advice-ref="xxxTxAdvice" pointcut-ref="allBusiness"/>
</aop:config>

AbstractHibernateRepository.java:

public abstract class AbstractHibernateRepository<E extends Entity, S extends Serializable> extends HibernateDaoSupport {
...
       @SuppressWarnings("unchecked")
protected E get(final DetachedCriteria detachedCriteria) {
    return (E) getHibernateTemplate().execute(new HibernateCallback<E>() {

        public E doInHibernate(Session session) {

            Criteria criteria = detachedCriteria.getExecutableCriteria(session);
            criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
            return (E) criteria.uniqueResult();
        }
    });
}
...
}

【问题讨论】:

    标签: java spring hibernate classcastexception


    【解决方案1】:

    升级到 Spring Boot 2.4.0 后遗留代码也面临同样的问题。通过使用 entityManager.unwrap(SessionImplementor.class) 检索要用于我的场景中的 DetachedCriteria 的会话来修复。

    【讨论】:

    • 谢谢。它适用于 Spring Boot 2.4.2。
    【解决方案2】:

    如果有人对FullTextEntityManager 有此问题,则@Gardella 的答案有效,但是,此link 建议将 Hibernate Search ORM 依赖项更新为 5.11.6.Final,这也解决了该问题。

    【讨论】:

      【解决方案3】:

      HibernateTemplate#doExecute

      enforceNativeSession - 是否强制将原生 Hibernate Session 暴露给回调代码

      你可以在GrepCode看到:

      protected Session createSessionProxy(Session session) {
          return (Session) Proxy.newProxyInstance(
          session.getClass().getClassLoader(), new Class<?>[] {Session.class},
          new CloseSuppressingInvocationHandler(session));
      }
      

      创建的代理只实现了接口Session,而不是接口SessionImplementor

      您必须将HibernateTemplate#execute 替换为HibernateTemplate#executeWithNativeSession

      【讨论】:

      • 太棒了。我知道它必须是单行的。非常感谢您的耐心等待。
      猜你喜欢
      • 2014-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-24
      • 1970-01-01
      • 2012-03-08
      相关资源
      最近更新 更多