4

私はアイデアを使い果たしました、グーグルも助けませんでした。ユースケースは些細なことのようですが、ClassCastExceptionで失敗します。何が間違っているのかわかりません。特定のカテゴリに一致する最初の要素を返す簡単な方法があります。見てみましょう。

private Category selectElement(List<? extends Category> results, Code code) {
    return selectFirst(results, having(on(Category.class).getCode(), is(code)));
}

実行すると、このスタックの最上位になります。

java.lang.ClassCastException: name.wilu.logic.report.utils.SheetLoader$Category$$EnhancerByCGLIB$$3a35aefc cannot be cast to net.sf.cglib.proxy.Factory
at ch.lambdaj.proxy.ClassImposterizer.createProxy(ClassImposterizer.java:134)
at ch.lambdaj.proxy.ClassImposterizer.imposterise(ClassImposterizer.java:101)
at ch.lambdaj.proxy.ProxyUtil.createProxy(ProxyUtil.java:52)
at ch.lambdaj.function.argument.ArgumentsFactory.createPlaceholder(ArgumentsFactory.java:68)
at ch.lambdaj.function.argument.ArgumentsFactory.registerNewArgument(ArgumentsFactory.java:58)
at ch.lambdaj.function.argument.ArgumentsFactory.createArgument(ArgumentsFactory.java:50)
at ch.lambdaj.function.argument.ArgumentsFactory.createArgument(ArgumentsFactory.java:39)
at ch.lambdaj.Lambda.on(Lambda.java:63)

エンティティを保持しているhibernateの永続コレクションを操作するためにlambdaJを使用しているときに、同じ問題が発生しました。すでにプロキシであるオブジェクト(コレクション内のエンティティ)のプロキシに問題がある可能性があると想定して、あきらめました。カテゴリとすべての継承されたクラスは、結果トランスフォーマーとして休止状態に渡されるpojoであるため、私は間違っていたようです。

そのような行動の理由は何でしょうか?何か考えはありますか?

(私は最新のlambdaj-2.4を使用しています)。

マリオのリクエストを満たすために追加されました

コードは単純な列挙型です。カテゴリはさまざまなカテゴリの基本クラスであり、コードフィールドがあります。さらに、これはパブリック静的クラスであり、すべての継承クラスと同じです(重要な場合)。

失敗したテストを提供しようとします。

追加情報を提供するために再度編集します。 私の友人がコードを調べて、この問題に新鮮な明るい光を当てました。

私は最初から私たちの控除の道を再現しようとします。

//与えられた

アプリケーションは2つの部分に分かれています。1つはベースアプリケーション(モデルファイルを保持)とWebアプリケーション(バッキングBeanなどのUI接続ファイルを保持)です。 カテゴリとコードはモデルクラスであるため、ベースアプリケーションに配置されます。次に、いくつかのWebロジックの目的でサービスを提供するバッキングBeanがあり、特にそのBeanまたはそのコラボレーターがselectを呼び出します。

// いつ

アプリケーションをWebサーバーにデプロイしています!私の場合はJBossです。クラスはローダーによって読み取られますが、私が気付いていない非常に複雑なことが起こり、すべてアプリケーションを実行します。私はいくつかのWebアクションを実行し、そのバッキングBeanのメソッドが呼び出されます

 selectFirst(results, having(on(Category.class).getCode(), is(code)));

アプリケーションのWeb部分から。

これが魔法です。Category.classとCode.classは、アプリケーションのロード時にUnifiedClassLoaderによってロードされました。on(Category.class)メソッドを使用しており、Categoryのプロキシが構築されます。いくつかの本当に絡み合ったロジックがそれを行うために利用されています。最も重要なのは、プロキシが装備されていることです。

setThreadsCallbacks(Callback[]callbacks) 

メソッドですが、Callback.classはそのクラスローダーから取得されます

 aCategory.getClass.getClassLoader()

したがって、最初にそのクラスであるUnifiedClassLoaderをロードしたのはクラスローダーです。これがすべてきれいに行われたので、私たちはついに電話します

 getFirstInstance()

リフレクションを使用すると、次を探しているプロキシクラスが参照されます。Proxy.getDeclaredMethod( "setThreadsCallbacks"、new Class [] {Callback []。class});

私は事実を省略します、私は理解していません

 new Class[]{ Callback[].class }

この場合に重要なのは、Callback.classがUnifiedClassLoaderによって提供されないことです。アプリケーションはWebタイヤで実行されるため、Callback.classの呼び出しはWebアプリごとに行われます。クラスローダーとreturedCallback.classは、前述のsetThreadsCallbacks関数の引数として以前に配置されたものとは異なります。反射は残酷に失敗します。

Category.class != Category.class //these two were provided by different classLoaders

そのため、失敗したテストを提供できませんでした。(同じクラスローダー)。

その場合の解決策はないと思います。

4

1 に答える 1

1

同様の問題が発生しました。(スローされた同じ例外:java.lang.ClassCastException:XXX $ Category $$ EnhancerByCGLIB $$ XXXをnet.sf.cglib.proxy.Factoryにキャストできません)

私の場合、CGLibライブラリが複製された(または3倍になった)問題であることが判明しました。私たちは次のように持っていました:

  • JBoss(4.2.3)ライブラリのcglib.jar
  • アプリケーションWebライブラリのcglib-nodep.jar(WARファイル)
  • アプリケーションWebライブラリのlabmdaj-2.4-with-dependencies.jar。

次に、Lambda.on(SomeClass.class)を使用すると、CGLibのEnhancerクラスでこのメソッドを取得します。

private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException {
        return type.getDeclaredMethod(methodName, new Class[]{ Callback[].class });
}

ここでmethodName = "CGLIB$SET_THREAD_CALLBACKS" 、typeは、でラップされたSomeClassEnhancerです。

「CGLIB$SET_THREAD_CALLBACKS」メソッドはラップされたタイプで存在していましたが、getDeclaredMethod()はnullを返しました。getDeclaredMethod()内で、2つのnet.sf.cglib.proxy.Callback.classインスタンスの比較が行われたようです。また、1つはcglib.jar(JBoss)からロードされ、もう1つはcglib-nodep.jar(webapp)からロードされたため、これらは異なっていました。

解決策は、冗長なcglib-nodep.jarを削除し、lambda-2.4-with-dependencies.jarをlambda-2.4.jarに置き換えることでした。これで、すべてのCGLibクラスが共通の場所からロードされ、問題はなくなりました。

于 2013-02-04T12:17:13.220 に答える