![](/img/trans.png)
[英]How can i get my CGLIB proxied classes working with spring framework's ReflectionUtils?
[英]Spring, CGLIB: why can't a generic class be proxied?
我想問一下異常的根本原因 :
Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to
java.lang.reflect.ParameterizedType
當我們讓Spring為類生成代理時(即在事務管理器上設置proxy-target-class="true"
,這會在Spring中發生:
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true"/>
並且要代理的類是參數化的類,即
public class SomeDAOImpl<SomeEntity> implements SomeDAO ...
例如,可以在以下問題中閱讀全文: 抽象DAO模式和Spring的“代理不能轉換為...”問題!
問題: Spring為什么不能代理此類? 是因為它使用了舊的代碼生成庫? 因為類型擦除? 如果SomeDAOImpl
不是通用類,它將成功(我檢查過)。
請不要這樣回答:“您應該代理接口,而不是類”。 我知道。
這看起來像一個Spring / CGLIB問題,但問題實際上出在您的構造函數中! 我猜您正在嘗試獲取參數類型,以便可以將其提供給實體管理器(或您要使用的任何持久性框架)。 我還猜到這樣做是要調用getGenericSuperclass()
並將其強制轉換為ParameterizedType?
方法的行為方式取決於類。 事實證明,並非所有Class對象都實現ParameterizedType接口(我同意,這很奇怪)。 生成的CGLIB代理不保留泛型信息。 看起來像:
public class SomeDAOImplProxy extends SomeDAOImpl
我實際上不知道為什么CGLIB代理不保留通用名稱,因為CGLIB代理的細節非常復雜。 這樣做根本不可能。 也有可能這樣做並不是他們的優先考慮。
這是一個簡單的實驗,它使Spring和CGLIB脫穎而出,但仍然出現該錯誤。
public static void main(String [] args) {
List<Object> fooList = new ArrayList<Object>();
String fooString = "";
System.out.println((ParameterizedType)fooList.getClass().getGenericSuperclass());
System.out.println((ParameterizedType)fooString.getClass().getGenericSuperclass());
}
由於CGLIB子類化了您的類以生成代理,因此您必須獲取超類的通用超類以獲取ParameterizedType
:
public class MyCglibProxiedBean<T> {
private final Class<T> paramClass;
public MyCglibProxiedBean() {
Type genericSuperClass = getClass().getGenericSuperclass();
// Get the generic super class of the super class if it's a cglib proxy
if (getClass().getName().contains("$$EnhancerByCGLIB$$")) {
genericSuperClass = getClass().getSuperclass().getGenericSuperclass();
}
this.paramClass = (Class<T>) ((ParameterizedType) genericSuperClass).getActualTypeArguments()[0];
}
}
我們使用的解決方案與James的答案類似,但恕我直言有點籠統:
Type genericSuperClass = repositoryClass.getGenericSuperclass();
ParameterizedType parametrizedType;
if (genericSuperClass instanceof ParameterizedType) { // class
parametrizedType = (ParameterizedType) genericSuperClass;
} else if (genericSuperClass instanceof Class) { // in case of CGLIB proxy
parametrizedType = (ParameterizedType) ((Class<?>) genericSuperClass).getGenericSuperclass();
} else {
throw new IllegalStateException("class " + repositoryClass + " is not subtype of ParametrizedType.");
}
@SuppressWarnings("unchecked")
Class<T> entityClass = (Class<T>) parametrizedType.getActualTypeArguments()[0];
return entityClass;
我設法用以下代碼解決了這個問題:
Type t = getClass();
do {
t = ((Class<T>) t).getGenericSuperclass();
} while (!(t instanceof ParameterizedType));
ParameterizedType pt = (ParameterizedType) t;
actualGenericType = (Class<T>) pt.getActualTypeArguments()[0];
我認為這是一個更干凈的解決方案,因為它不使用CGLIB的內部結構。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.