1

Java である Bean を別の Bean にコピーしたいと思います。classloading-juggler フレームワーク内にあり、両方のクラスが現在のクラスローダーとは異なる別のクラスローダーによってロードされるという問題。

最も効率的な方法で行う必要があるため、リフレクションベースではなく、バイトコード生成ソリューション (cglib BeanCopier など) を使用するのが最善の方法です。

問題は、この場合 cglib BeanCopier が機能しないことです。それを示す最も簡単なコードは次のとおりです。

URL classesUrl = new File("/directory/with/class-files-for-Person").toURL();
Class<?> c1 = new URLClassLoader(new URL[] {classesUrl}).loadClass("Person");
Class<?> c2 = new URLClassLoader(new URL[] {classesUrl}).loadClass("Person");
Object o1 = c1.newInstance();
Object o2 = c2.newInstance();
BeanCopier copier = BeanCopier.create(o1.getClass(), o2.getClass(), false);
copier.copy(o1, o2, null);

それは例外を与えます:

Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to Person
at net.sf.cglib.empty.Object$$BeanCopierByCGLIB$$da60538e.copy(<generated>)
at Main.main(Main.java:22)

私はそれを解決する方法を見つけています。私の場合、両方のクラスは同じですが、カスタム クラスローダーがロードされています。また、プロパティには java.* からの privimives とクラスのみが含まれます (したがって、これらは標準のクラスローダーによってロードされます)。

4

1 に答える 1

1

これは、cglib にクラス名のみを考慮し、クラス ローダーを確認しないバグがあるように思えます。実際のところ、cglib は使用していないときのバグでいっぱいEnhancerですBeanCopier。さらに悪いニュースがあります。cglib はあまり積極的に開発されていないため、バグを修正するためにできる最善のことは、自分で試してみることでした。

あなたが試すことができるのは、このコンバーターをアクティブにするために、3 番目のConverter引数としてa を追加しcopy、3 番目のコンストラクター引数を に変更することです。trueが単に引数Converterを返すようにします。valueこのソリューションの欠点は、値がコピーされるたびにプリミティブがボックス化され、ボックス化されなくなり、パフォーマンスが低下することです。

ただし、良いニュースがあります。HotSpot などの最新の JVM は、インフレーションと呼ばれる概念を認識しています。特定のリフレクションが複数回 (現在の HotSpot JVM で 15 回以上) 適用されると、インフレが適用されます。次に、JVM は、このリフレクション呼び出しに対応するバイト コードを作成し、それを生成されたバイト コードに置き換えます。これはまさに が行うことですBeanCopierが、(明らかに) バグがあります。このため、これBeanCopierは古いニュースです。最新の JVM は、この最適化を自分自身で適用できるほどスマートです。インフレーションについて詳しく知りたい場合は、たとえばHotSpot 関連の javadocを参照してください。

さらに読むために、興味深いと思われるこの記事を見つけました。

于 2013-12-29T00:26:05.660 に答える