web-dev-qa-db-ja.com

同じクラスにキャストするときのClassCastException

2つの異なるJavaプロジェクトがあり、1つには_dynamicbeans.DynamicBean2_と_dynamic.Validator_の2つのクラスがあります。

他のプロジェクトでは、これらのクラスの両方を動的にロードし、Objectに保存します

_class Form {
    Class beanClass;
    Class validatorClass;
    Validator validator;
}
_

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

_portletRequest.setAttribute("DynamicBean2", bean);
_

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

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

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

.getClass()を使用してそのクラスを確認してください_dynamicbeans.DynamicBean2_を取得します。これは、キャストしたいクラスですが、ClassCastExceptionを取得しようとしています。

これを取得する理由は何ですか?

51
Jaime Garcia

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

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

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

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

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

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

57
waxwing

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

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

12
Robin

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にコピーすることでも問題は解決しました。別の解決策は、casll digester.setClassLoader(MyTemplate.class.getClassLoader())でしたが、このコンテキストでは非常にい解決策のように感じます。

2
Emil Lundberg

WildFly 10.1で同じmy.package.MyClass cannot be cast to my.package.MyClassを使用しており、私が理解しているように、@ Emil Lundbergが彼の答えで説明したことと反対のことをしました。

modulemy.package.MyClassを含む)を依存関係としてmy.war/WEB-INF/jboss-deployment-structure.xmlに追加しました

<dependencies>
    ...
    <module name="my.package"/>
</dependencies>

そして、対応するjarmy.war/WEB-INF/libから削除し、WARを再デプロイすると、コードは期待どおりに機能しました。

したがって、問題を確実に解決しました。ここで、たとえば、[〜#〜] war [〜#〜]の更新バージョンがアセンブルされたときに、問題が再発しないことを確認する必要があります。展開されました。

このため、それらのソース[〜#〜] war [〜#〜]では、それらに<scope>provided</scope>を追加する必要がありますjarin pom.xml。これにより、次回my.warが修正/拡張コードを挿入して再アセンブルされるときに、このjarmy.war/WEB-INF/libに。

0
RAM237

私は同じ問題を抱えていましたが、ついにJava.netで回避策を見つけました。

すべてコピーorg.Eclipse.persistence jarからのファイルglassfish4/glassfish/modulesからWEB-INF/lib。次にglassfish-web.xml、およびclass-delegateからfalseへ。

私のために働いた!

0
Adrien Dos Reis

別のEJBからのEJBルックアップでも同じ問題が発生しました。 EJBクラス構成に@Remote(MyInterface.class)を追加することを解決しました

0
user3402702

異なるマシンで複数のJBossインスタンスを使用しているときに同じ問題が発生しました。残念なことに、私は以前この投稿に出くわしませんでした。
別のマシンにデプロイされたアーティファクトがあり、そのうちの2つは同じ名前のクラスローダーを宣言しました。

なぜClassCastExceptionがスローされて、関連するクラスローダーが言及されないのですか? -それは非常に有用な情報になると思います。
将来、このようなものが利用可能になるかどうかは誰にもわかりませんか? 20-30のアーティファクトのクラスローダーを確認する必要はありません。または、例外テキストで見逃したものがありますか?

[〜#〜] edit [〜#〜]: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

0
Andrei

別のオプション:

Weblogicで私に起こったが、他のサーバーでも同様に起こる可能性があると思います-あなたが(ちょうど)「公開」すると、一部のクラスが再ロードされます。代わりに、すべてのクラスが一緒に再ロードされるように「クリーン」を実行します。

0
Yogev Levy

JAXBとJBoss AS 7.1でも同様の問題がありました。問題と解決策は次のとおりです: javax.xml.bind.JAXBException:Class ***またはそのスーパークラスはこのコンテキストで認識されています 。与えられた例外はorg.foo.bar.ValueSetをorg.foo.bar.ValueSetにキャストできないことでした

0
John

Springbootプロジェクトでspring-boot-devtoolsに依存関係を追加すると、この問題が発生しました。依存関係を削除すると、問題はなくなりました。この時点での最良の推測は、spring-boot-devtoolsが新しいクラスローダーを持ち込み、新しいクラスローダーが一部のスレッドで使用されていない特定の場合に、異なるクラスローダー間でクラスキャストの問題が発生することです。

参照: Springブートdevtoolsに関連するドーザーマップの例外

0
K.Nicholas

Wildfly 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インターフェースが問題なく見つかり、問題なくメソッドを実行します(同じコンテナー上の別のアプリケーションから)。ただし、モデルオブジェクトはマーシャリングされず、誤ってローカルインターフェイスを使用した場合は、別のクラスローダーから。

0
Meindert