1

例外の根本原因についてお聞きしたいです。

Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to  
java.lang.reflect.ParameterizedType

proxy-target-class="true"これは、Spring にクラスのプロキシを生成させる (つまり、トランザクション マネージャーで設定する) ときに Spring で発生します。

<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がジェネリック クラスでない場合は、成功します (確認しました)。

「クラスではなくインターフェイスをプロキシする必要があります」のように答えないでください。そんなこと知ってる。

4

4 に答える 4

5

これは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());
}
于 2011-12-12T13:42:18.920 に答える
5

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];
    }
}
于 2012-12-17T19:49:15.580 に答える
1

ジェームズの答えに似た解決策を使用しますが、IMHOはもう少し一般的です:

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;
于 2014-01-02T11:55:38.343 に答える
0

私はこのコードで問題を解決することができました:

Type t = getClass();
do {
  t = ((Class<T>) t).getGenericSuperclass();
} while (!(t instanceof ParameterizedType));
ParameterizedType pt = (ParameterizedType) t;
actualGenericType = (Class<T>) pt.getActualTypeArguments()[0];

CGLIB の内部構造を使用しないため、少しクリーンなソリューションだと思います。

于 2016-05-11T12:05:37.180 に答える