Hibernate/Spring 4 升级后无法将 ClassCastException Proxy36 转换为 SessionImplementor
ClassCastException Proxy36 cannot be cast to SessionImplementor after Hibernate/Spring 4 upgrade
编辑:我不是在问什么 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.doInHibernate(AbstractHibernateRepository.java:163)
...
这发生在 Hibernate 的 org.hibernate.criterion.DetachedCriteria
class:
/**
* 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
。
休眠-context.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>
交易-context.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();
}
});
}
...
}
enforceNativeSession
- whether to enforce exposure of the native Hibernate Session to callback code
如您所见 GrepCode:
protected Session createSessionProxy(Session session) {
return (Session) Proxy.newProxyInstance(
session.getClass().getClassLoader(), new Class<?>[] {Session.class},
new CloseSuppressingInvocationHandler(session));
}
创建的代理只实现了接口Session
,没有实现接口SessionImplementor
。
你必须替换 HibernateTemplate#execute with HibernateTemplate#executeWithNativeSession。
升级到 spring 引导 2.4.0 后遗留代码面临同样的问题。在我的场景中,通过使用 entityManager.unwrap(SessionImplementor.class)
检索要用于 DetachedCriteria 的会话来修复。
如果有人遇到 FullTextEntityManager
的这个问题,@Gardella 的回答有效,但是,这个 link 建议将 Hibernate Search ORM 依赖项更新到 5.11.6.Final,这也解决了这个问题。
编辑:我不是在问什么 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.doInHibernate(AbstractHibernateRepository.java:163)
...
这发生在 Hibernate 的 org.hibernate.criterion.DetachedCriteria
class:
/**
* 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
。
休眠-context.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>
交易-context.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();
}
});
}
...
}
enforceNativeSession
- whether to enforce exposure of the native Hibernate Session to callback code
如您所见 GrepCode:
protected Session createSessionProxy(Session session) { return (Session) Proxy.newProxyInstance( session.getClass().getClassLoader(), new Class<?>[] {Session.class}, new CloseSuppressingInvocationHandler(session)); }
创建的代理只实现了接口Session
,没有实现接口SessionImplementor
。
你必须替换 HibernateTemplate#execute with HibernateTemplate#executeWithNativeSession。
升级到 spring 引导 2.4.0 后遗留代码面临同样的问题。在我的场景中,通过使用 entityManager.unwrap(SessionImplementor.class)
检索要用于 DetachedCriteria 的会话来修复。
如果有人遇到 FullTextEntityManager
的这个问题,@Gardella 的回答有效,但是,这个 link 建议将 Hibernate Search ORM 依赖项更新到 5.11.6.Final,这也解决了这个问题。