61

2 つの異なる Java プロジェクトがあり、1 つには 2 つのクラスがあります:dynamicbeans.DynamicBean2dynamic.Validator.

もう一方のプロジェクトでは、これらのクラスを両方とも動的にロードし、Object

class Form {
    Class beanClass;
    Class validatorClass;
    Validator validator;
}

次に、Validator使用してオブジェクトを作成し、それvalidatorClass.newInstance()を保存してからvalidator、Bean オブジェクトを使用して作成し、beanClass.newInstance()それをセッションに追加します。

portletRequest.setAttribute("DynamicBean2", bean);

Formプロジェクトのライフサイクル中にvalidator.validate()、以前に作成した Bean オブジェクトをセッションからロードする を呼び出します (私は Websphere Portal Server を実行しています)。このオブジェクトを にキャストしようとするDynamicBean2と、ClassCastException で失敗します。

を使用してオブジェクトをセッションから引き戻すと、

faces.getApplication().createValueBinding("#{DynamicBean2}").getValue(faces);

.getClass()I getを使用してクラスを確認しますdynamicbeans.DynamicBean2。これは私がキャストしたいクラスですが、試してみると ClassCastException が発生します。

これを取得する理由はありますか?

4

11 に答える 11

65

私はあなたのプログラムフローの説明に完全に従っていませんが、通常、 ClassCastExceptions を取得すると、あるクラスローダーでクラスをロードしたことを説明できず、別のクラスローダーによってロードされた同じクラスにキャストしようとします。これは機能しません。これらは JVM 内の 2 つの異なる Class オブジェクトによって表され、キャストは失敗します。

WebSphere でのクラスローディングに関する記事があります。それがあなたのアプリケーションにどのように適用されるかは言えませんが、考えられる解決策はいくつかあります。私は少なくとも考えることができます:

  1. コンテキスト クラス ローダーを手動で変更します。適切なクラスローダーへの参照を実際に取得できる必要がありますが、これはあなたのケースでは不可能な場合があります。

    Thread.currentThread().setContextClassLoader(...);
    
  2. 階層の上位にあるクラスローダーによってクラスがロードされていることを確認してください。

  3. オブジェクトをシリアライズおよびデシリアライズします。(うん!)

ただし、特定の状況にはおそらくより適切な方法があります。

于 2009-05-05T18:46:27.470 に答える
14

クラス オブジェクトは異なるクラスローダにロードされたため、各クラスから作成されたインスタンスは「互換性がありません」と見なされます。これは、多くの異なるクラスローダが使用され、オブジェクトが渡される環境でよくある問題です。これらの問題は、Java EE およびポータル環境で簡単に発生する可能性があります。

クラスのインスタンスをキャストするには、キャストされるオブジェクトにリンクされたクラスが、現在のスレッド コンテキスト クラスローダーによってロードされたものと同じである必要があります。

于 2009-05-05T18:47:34.970 に答える
2

Apache Commons Digester を使用して XML からオブジェクトのリストを作成しようとすると、A2AClassCastException の問題が発生しました。

List<MyTemplate> templates = new ArrayList<MyTemplate>();
Digester digester = new Digester();
digester.addObjectCreate("/path/to/template", MyTemplate.class);
digester.addSetNext("/path/to/template", "add");
// Set more rules...
digester.parse(f); // f is a pre-defined File

for(MyTemplate t : templates) { // ClassCastException: Cannot cast mypackage.MyTemplate to mypackage.MyTemplate
    // Do stuff
}

上で述べたように、原因は、ダイジェスターがプログラムの残りの部分と同じ ClassLoader を使用していないことです。これを JBoss で実行したところ、commons-digester.jar が JBoss の lib ディレクトリではなく、webapp の lib ディレクトリにあることがわかりました。jar を mywebapp/WEB-INF/lib にコピーしても問題は解決しました。別の解決策は、digester.setClassLoader(MyTemplate.class.getClassLoader()) を casll することでしたが、このコンテキストでは非常に醜い解決策のように感じます。

于 2011-11-25T15:21:08.633 に答える
0

異なるマシンで複数のJBossインスタンスを使用しているときに同じ問題が発生しました。悪いことに、私は以前にこの投稿に出くわしませんでした。
異なるマシンにアーティファクトがデプロイされ、そのうちの2つは同じ名前のクラスローダーを宣言しました。クラスローダー名の1つを変更すると、すべてが正常に機能しました=>コピーアンドペーストに注意してください。

スローされたClassCastExceptionが、関連するクラスローダーについて言及していないのはなぜですか?-とても参考になると思います。
将来このようなものが利用可能になるかどうか誰かが知っていますか?20〜30個のアーティファクトのクラスローダーをチェックする必要があるのはそれほど楽しいことではありません。または、例外テキストで見逃したものはありますか?

編集:META-INF / jboss-app.xmlファイルを編集し、ローダーの名前を変更しました。一意の名前を付けるという考え方です。作業では、ビルド中にmaven({$ version})によって挿入されたバージョンと組み合わせたアーティファクトid(unique)を使用します。
動的フィールドの使用はオプションですが、同じアプリケーションの異なるバージョンをデプロイする場合に役立ちます。

<jboss-app>
   <loader-repository> 
   com.example:archive=unique-archive-name-{$version}
   </loader-repository> 
</jboss-app>

ここでいくつかの情報を見つけることができます:https ://community.jboss.org/wiki/ClassLoadingConfiguration

于 2012-02-23T12:40:24.387 に答える
0

私は同じ問題を抱えていましたが、最終的に java.net で回避策を見つけました:

からにすべてのorg.eclipse.persistence jarファイルをコピーします。次に、 に移動し、に設定します。glassfish4/glassfish/modulesWEB-INF/libglassfish-web.xmlclass-delegatefalse

私のために働いた!

于 2014-11-17T13:27:13.300 に答える
0

私は野生のEJBで同じ問題を抱えていました。EJBはオブジェクトのリストを返し、リモートとローカルのインターフェースを持っていました。リスト内のオブジェクトをキャストしようとする時点までは正常に機能していた Local インターフェイスを誤って使用しました。

ローカル/リモート インターフェイス:

public interface DocumentStoreService {

    @javax.ejb.Remote
    interface Remote extends DocumentStoreService {
    }

    @javax.ejb.Local
    interface Local extends DocumentStoreService {
    }

EJB Bean:

@Stateless
public class DocumentStoreServiceImpl implements DocumentStoreService.Local, DocumentStoreService.Remote {

EJB の正しいスプリング ラッパー:

<bean id="documentStoreService" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
    <property name="jndiName" value="java:global/dpc/dpc-ejb/DocumentStoreServiceImpl!santam.apps.dpc.service.DocumentStoreService$Remote"/>
    <property name="businessInterface" value="santam.apps.dpc.service.DocumentStoreService$Remote"/>
    <property name="resourceRef" value="true" />
</bean>

$Remote に注意してください。これを $Local に変更すると、Local インターフェイスが問題なく検出され、(同じコンテナー上の別のアプリケーションから) 問題なくメソッドが実行されますが、モデル オブジェクトはマーシャリングされず、誤ってローカル インターフェイスを使用した場合は、別のクラス ローダーから。

于 2017-02-21T08:25:13.003 に答える