【问题标题】:Adding @Transactional causes "java.lang.ClassCastException-->java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType" exception添加@Transactional 导致“java.lang.ClassCastException-->java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType”异常
【发布时间】:2026-01-30 23:10:01
【问题描述】:

我正在使用 Spring 3.2.11.RELEASE。我有一个像下面这样的课程......

@Repository("AssessmentImageDao")
@Transactional
public class MyObjectDao extends GenericDAO<MyObject> 
{

超类所在的位置

public GenericDAO() {
    this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}

但是,这会导致下面的异常...

[ERROR]: org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@62b9a65b] to prepare test instance [com.myco.MyTest@7a252cf1]
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:122)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MyObjectDao' defined in file [/Users/davea/Dropbox/workspace/core/target/classes/org/mainco/subco/myproject/dao/MyObjectDao.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class org.mainco.subco.myproject.dao.MyObjectDao]: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.ClassCastException-->java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:636)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:934)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:120)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:102)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:246)
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
    ... 25 more

有没有办法重写构造函数来避免这种异常,或者做一些其他的全局配置来解决这个问题?我正在尝试对 GenericDao 类的每个子类进行重新编码。

【问题讨论】:

  • 你用org.springframework.transaction.annotation.Transactional代替javax.transaction.Transactional吗?
  • 很好的区分,是的,我正在使用 org.springframework.transaction.annotation.Transactional 。

标签: spring dao autowired transactional


【解决方案1】:

问题在于@Transactional 注释是通过在类层次结构中添加另一层来实现的——一个扩展MyObjectDao 以实现事务行为的代理类。对于这个代理类的对象,this.getClass()是代理类,其getGenericSuperclass()是MyObjectDao本身,而不是参数化类型GenericDAO&lt;MyObject&gt;

你可以稍微改变一下逻辑,这样你就可以继续查找 getGenericSuperclass 链,直到找到 ParameterizedType - 如果父级是 Class,你尝试祖父级,等等。

或者,看看您是否可以将超类查找推迟到您第一次真正需要它时(调用其中一个 GenericDAO 方法时),而不是在构造函数中进行。虽然生成的代理类扩展了 MyObjectDao,但它实际上从未在 this 上调用其任何超类方法。代理拦截所有方法调用,执行事务逻辑,然后将业务逻辑委托给单独的目标对象,该目标对象直接是 MyObjectDao 的实例,而不是子类。

【讨论】:

    【解决方案2】:

    您还可以使用多态性并在GenericDAO 中创建一个public abstract Class&lt;? extends MyObject&gt; getHandledType() 方法,并使每个实现都自我介绍。

    或者使用 Spring Data。

    【讨论】:

    • 你能提供一个编码示例来说明它是如何工作的吗?
    • @DaveA 它需要“重新编码 GenericDao 类的每个子类”以添加新方法...