JavaSpring,CGLIB:为什么不能代理泛型类?
我想问一下异常的根本原因:
Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to
java.lang.reflect.ParameterizedType
在Spring中,当我们让Spring为类生成代理(即在事务管理器上设置proxy-target-class="true"
)时,会发生这种情况:
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true"/>
当要代理的类是参数化类时,即
public class SomeDAOImpl<SomeEntity> implements SomeDAO ...
例如,完整的故事可以在这个问题中阅读:Abstract DAO pattern and Spring's "Proxy cannot be cast to ..." problem!
问题:为什么Spring不能代理这个类?是因为它使用旧的代码生成库吗?因为类型擦除?如果SomeDAOImpl
不是泛型类,它将成功(我检查了它)
请不要这样回答:“您应该代理接口,而不是类”。我知道
# 1 楼答案
这看起来像是Spring/CGLIB的问题,但问题实际上在您的构造函数中!我猜您正在尝试获取参数类型,以便将其提供给实体管理器(或您尝试使用的任何持久性框架)。我还猜,要做到这一点,您需要调用
getGenericSuperclass()
并将其转换为参数化类型该方法的行为方式取决于类。事实证明,并不是所有类对象都实现ParameterizedType接口(我同意,这很奇怪)。生成的CGLIB代理不保留泛型信息。它看起来像:
我不知道CGLIB代理为什么不保留泛型,因为CGLIB代理的细节非常复杂。这可能是根本不可能做到的。也可能是这样做对他们来说不是优先事项
下面是一个简单的实验,它去掉了Spring和CGLIB,但仍然得到了那个错误
# 2 楼答案
我用这段代码解决了这个问题:
我认为这是一个更干净的解决方案,因为它不使用CGLIB的内部结构
# 3 楼答案
我们使用类似于James's answer的解决方案,但更一般一点:
# 4 楼答案
由于CGLIB对类进行子类化以生成代理,因此必须获得超类的泛型超类才能获得^{: