クラス・ロード例外
アプリケーションの開発時、あるいはインストール済みアプリケーションの開始時に発生するクラス・ロード・エラーの種類を特定してください。
ClassCastException
クラス・キャスト例外は、以下の条件が存在する場合に発生し、次のアクションによって修正することができます。
- ソース・オブジェクトのタイプは、 ターゲット・クラス (タイプ) のインスタンスではありません。
- ソース・オブジェクト (クラス) をロードするクラス・ローダーが、ターゲット・クラスをロードするクラス・ローダーと異なります。
- アプリケーションが、 絞り込み操作を実行しないか、または実行が不適切です。
- ソース・オブジェクトのタイプは、 ターゲット・クラス (タイプ) のインスタンスではありません。
- これは、典型的なクラス・キャスト例外です。キャスト・ステートメントの
ソース・オブジェクトがターゲット・クラス (タイプ) のインスタンスではないと診断するには、ソース・オブジェクト・クラスのクラス・シグニチャーを調査し、その先祖にターゲット・クラスを含まないこと、およびソース・オブジェクト・クラスが、ターゲット・クラスと異なることを確認します。
クラス情報を取得するには、単純な print ステートメントをコードに挿入します。以下に例を示します。
または、javap コマンドを使用します。以下に例を示します。System.out.println( source.getClass().getName() + “:” + target.getClass().getName() );
javap java.util.HashMap Compiled from "HashMap.java" public class java.util.HashMap extends java.util.AbstractMap implements java.util.Map,java.lang.Cloneable,java.io.Serializable {
- ソース・オブジェクト (クラス) をロードするクラス・ローダーが、ターゲット・クラスをロードするクラス・ローダーと異なります。
- ソース・オブジェクトのタイプがターゲット・クラスのインスタンスであるとすると、
クラス・キャスト例外が発生するのは、ソース・オブジェクトのクラスをロードするクラス・ローダーが、ターゲット・クラスをロードするクラス・ローダーと異なる場合です。
この状態は、WebSphere® Application Server ランタイム環境において、
ターゲット・クラスが複数のクラス・ローダーのクラスパスで可視である場合に
発生する可能性があります。
この問題を訂正するには、クラス・ローダーの問題を診断するのに使う「検索」および「クラス名で検索
(Search by class name)」コンソール・ページを使用します。
- 「検索」ページにアクセスします。 とクリックして、
- 「検索タイプ」に「クラス/パッケージ」」を選択します。
- 「検索語」に、2 つのクラス・ローダーによってロードされるクラスの名前を入力します。
- 「OK」をクリックします。
「クラス名で検索 (Search by class name)」ページが表示され
、クラスをロードするすべてのクラス・ローダーがリストされます。
複数のクラス・ローダーがリストされた場合は、ターゲット・クラスが複数のクラス・ローダーによってロードされています。 ソース・オブジェクトはターゲット・クラスのインスタンスであるため、 ソース・オブジェクト・クラスをロードするクラス・ローダーが、ターゲット・クラスをロードするクラス・ローダーと異なります。
- クラス・ローダー・ビューアー・ページに戻り、クラスパスを調べて、2 つの異なるクラス・ローダーがクラスをロードする理由を判別します。
- 該当するクラス・ローダーのみにクラスが見えるように、コードを修正します。
- アプリケーションが、 絞り込み操作を実行しないか、または実行が不適切です。
- クラス・キャスト例外は、アプリケーションがリモート・エンタープライズ Bean (EJB) オブジェクトを解決しているときに、
アプリケーション・コードが必要な絞り込み操作を実行しないために起こります。アプリケーションは、リモート・オブジェクトを検索した後で絞り込み操作を実行する必要があります。
アプリケーションを調査し、アプリケーションがリモート・オブジェクトを検索するかどうかを判別し、検索する場合には、検索の結果を絞り込みメソッドに送信します。
絞り込みメソッドは、EJB 2.0 プログラミング・モデルに従って呼び出される必要があります。特に、絞り込みメソッドに送信されるターゲット・クラスは、EJB の正確な最派生インターフェースでなければなりません。これは、 WebSphere Application Server ランタイム環境でのクラス・キャスト例外の 原因にもなります。アプリケーションを調査し、絞り込みメソッドに送信されるターゲット・クラスが、 正確な EJB タイプではなく、指定された EJB のスーパー・インターフェースとなっていないか判別します。そうである場合は、正確な EJB インターフェースで絞り込みを呼び出すようにアプリケーションを修正します。
最後に、絞り込み操作中に クラス・キャスト例外が発生する場合は、絞り込みメソッドが、ローカル・エンタープライズ Bean ではなく、 リモート EJB の検索結果に適用されていることを確認します。絞り込みは、ローカル検索には使用されません。 アプリケーションまたはモジュールのデプロイメント記述子を検査して、絞り込み検索対象のオブジェクトがローカル・オブジェクトでないことを確認します。
ClassNotFoundException
class not found exception は、以下の条件が存在する場合に発生し、次のアクションを実行するこ とによって修正できます。
- クラスが コンテキスト・クラス・ローダーの論理クラスパスで可視ではありません。
- 見つからないクラスは、現在のスレッドに関連付けられている
クラス・ローダーの論理クラスパスに存在しません。
論理クラスパスは、ロード操作がクラス・ローダーで呼び出されたときに検索されるすべてのクラスパスの累積です。
この問題を訂正するには、「検索」ページを使用してクラス名および Java™
アーカイブ (JAR) 名で検索します。
- 「検索」ページにアクセスします。 とクリックして、
- 「検索タイプ」に「クラス/パッケージ」」を選択します。
- 「検索語」に、見つからないクラス名を入力します。
- 「OK」をクリックします。 「クラス名で検索 (Search by class name)」ページが表示され 、クラスをロードするすべてのクラス・ローダーがリストされます。
- ページを調べてそのクラスがリストに存在しているかどうか確認します。
- リストにそのクラスがない場合は、「検索」ページに戻ります。 「検索語」に、クラスの .jar ファイルの名前を入力し、「検索タイプ」で「JAR/ディレクトリー (JAR/Directory)」を選択します。
- 「OK」をクリックします。「Search by Path」ページが表示され、JAR ファイルを格納しているすべてのディレクトリーがリストされます。
JAR ファイルがリストにない場合、そのクラスは論理クラスパスにないか、読み取り不能か、代替クラスが既にロードされている場合があります。 クラスを、ロードできるロケーションに移動します。
- アプリケーションが クラス・ローダー API を間違って使用します。
- アプリケーションは、クラス・ローダーのインスタンスを取得し、
そのクラス・ローダーの loadClass メソッドを呼び出すか、またはそのクラス・ローダーで Class.forName(class_name、initialize、class_loader) を呼び出すことができます。アプリケーションで、クラス・ローダーのアプリケーション・プログラミング・インターフェース (API) を間違って使用している場合があります。例えば、
クラス名が間違っている、クラスがそのクラス・ローダーの論理クラスパスにない、
または間違ったクラス・ローダーを使用している、などが考えられます。
この問題を 解決するには、クラスが存在するかどうか、およびアプリケーションが適切にクラス・ローダー API を使用しているかどうかを判別します。クラスがロードされているかどうかを判別するには、クラスがコンテキスト・クラス・ローダーの論理クラスパスで可視ではありませんのステップを実行します。 クラスがロードされていなかった場合は、アプリケーションの修正を試みてクラスがロードするかを確認します。 クラスが適切なアクセス権のある持つクラスパスにあり、別のファクトリ ー・クラスによってオーバーライドされていない場合は、クラスをロ ードするのに使用する API を調べます。
- 「検索」ページにアクセスします。 とクリックして、クラス・ローダーの
- 「検索タイプ」に「クラス/パッケージ」」を選択します。
- 「検索語」に、クラス名を入力します。
- 「OK」をクリックします。 「クラス名で検索 (Search by class name)」ページが表示され 、クラスをロードするすべてのクラス・ローダーがリストされます。
- ページを調べてそのクラスがリストに存在しているかどうか確認します。
- クラスがリストにあり、ClassNotFound 例外がスローされた場合は、.jar ファイルかクラスは正しいコンテキストにないか、現行コンテキストで間違った API 呼び出しが使用されています。リストにそのクラスがない場合は、「検索」ページに戻り、以下を 実行します。
- 例外を生成したクラス、すなわち、Class.forName を呼び出すクラスを検索します。
- どのクラス・ローダーがクラスをロードするかを確認します。
- クラス・ローダーがアクセス権を持っているかどうか、またはクラス・ローダーのクラスパスを実行することによって見つからないクラスをロードできるかどうかを判別します。
- 従属クラスが可視ではありません。
- クラス・ローダー clsldr がクラス cls をロードする場合、
Java 仮想マシン (JVM) は、clsldr を呼び出して cls が従属するクラスをロードします。
従属クラスは、clsldr の論理クラスパス上で可視である必要があります。可視でない場合は、例外が発生します。
このような状態が一般的に発生するのは、ユーザーが WebSphere Application Server クラスを
JVM に見えるようにしたか、またはアプリケーション・クラスを JVM または WebSphere
の拡張クラス・ローダーに見えるようにした場合です。以下に例を示します。
- クラス A はクラス B に従属しています。
- クラス A は、WebSphere 拡張クラス・ローダーに見えています。
- クラス B は、WAR モジュール・クラス・ローダーのローカル・クラスパス上では見えていますが、WebSphere 拡張クラス・ローダーのクラスパス上では見えていません。
JVM は、WebSphere 拡張クラス・ローダーを使用してクラス A をロードする場合、同じクラス・ローダーを使用してクラス B のロードを試み、結局、クラスが見つからないという例外を作成します。
以下の方法でこの問題を解決します。
- アプリケーション固有のクラスを適切なアプリケーションのクラス・ローダーに見えるようにします。
- 見つからなかったクラス (クラス B) を検索します。
- クラス B が適切なロケーションにある場合、クラス・ローダー・ビューアーで、従属クラス (クラス A) をロードするクラスの検索を行います。
- クラスがロードされており、ClassNotFound 例外がスローされていた
場合、.jar ファイルまたはクラスは適切なコンテキストにないか現行コンテキストで間違った API 呼び出しが使用されています。
クラスが見つからなかった場合は、以下を実行します。
- 例外を生成したクラス、すなわち、Class.forName を呼び出すクラスを検索します。
- どのクラス・ローダーがクラスをロードするかを確認します。
- クラス・ローダーがアクセス権を持っているかどうか、またはクラス・ローダーのクラスパスを実行することによって見つからないクラスをロードできるかどうかを判別します。
- 呼び出し元のクラス (クラス B) が JVM または WebSphere 拡張クラス・ローダーに見えていることを確認します。
NoClassDefFoundException
no class definition found 例外は、以下の条件が存在する場合に発生し、次のアクシ ョンを実行することによって修正できます。
- そのクラスが論理クラスパスにありません。
- 詳しくは、ClassNotFoundExceptionを参照してください。
- クラスはロードができません。
- クラスがロードできないのには、さまざまな理由があります。理由には、従属クラスをロードできない、従属クラスのフォーマットが間違っているか、クラスのバージョン番号が違うといったものがあります。
UnsatisfiedLinkError
リンケージ・エラーは以下の条件が存在する場合に発生し、次のアクションを実行することによって修正できます。
- ユーザーのアクションにより、エラーが発生しました。
System.mapLibraryName が間違ったライブラリー・ファイルを戻します。
- ネイティブ・ライブラリーが既にロードされています。
- 従属したネイティブ・ライブラリーが使用されました。
- ユーザーのアクションにより、エラーが発生しました。
いくつかのユーザー処置がリンケージ・エラーを発生させる場合があります。
- ライブラリーの拡張名がそのプラットフォームに対して正しくありません。
ライブラリーがダイナミック・リンク・ライブラリー名 library_name.dll を持っています。
ライブラリー名は、library_name.so または library_name.a です。
- System.loadLibrary に正しくないパラメーターが渡されています。
Name.dll という名前のダイナミック・リンク・ライブラリーをロードするには、Name が loadLibrary 呼び出しに渡される必要があります。
libName.so または libName.a という名前のライブラリーをロードするには、libName が loadLibrary 呼び出しに渡される必要があります。
- ライブラリーが可視ではありません。
- 最良の方法は、JVM クラス・ローダーを使用して、ネイティブ・ライブラリーを検索またはロードすることです。
WebSphere Application Server は、始動するときに、
Java ライブラリー・パス (java.library.path) を表示します。JVM クラス・ローダーでライブラリーをロードする場合は、Java ライブラリー・パスに、ネイティブ・ライブラリー・ファイルを含むパスが存在することを確認します。
このパスが存在しない場合は、プラットフォーム固有のネイティブ・ライブラリー環境変数、
またはサーバー・プロセス定義の java.library.path システム・プロパティーにパスを追加します。
通常、Java 仮想マシンは、System.loadLibrary() を呼び出すクラスをロードするクラス・ローダー xxx の findLibrary() を起動します。 xxx.findLibrary() が失敗すると、Java 仮想マシンは、JVM ライブラリー・パスを検索する JVM クラス・ローダーを使用してライブラリーを検索しようとします。 ライブラリーが見つからない場合は、Java 仮想マシンが UnsatisfiedLinkError 例外を作成します。
つまり、WebSphere クラス・ローダーでネイティブ・ライブラリー myNativeLib を見つけようとする場合は、System.loadLibrary(myNativeLib) を呼び出すクラスをロードするクラス・ローダーの nativelibpath において、そのライブラリーが可視である必要があります。 このような方法が、必要または適しているのは、次のような状態です。
データ・ソース・プロバイダーのネイティブ・ライブラリーは、WebSphere 拡張クラス・ローダーの nativelibpath で可視である必要があります。 この場合は、ネイティブ・ライブラリーを含むパスを、 データ・ソース・プロバイダー構成の「ネイティブ・ライブラリー・パス (Native library path)」設定に追加します。
- 共有ライブラリーの構成には、「ネイティブ・ライブラリー・パス (Native library path)」があります。共有ライブラリーは、アプリケーション固有ライブラリーのバージョン管理が可能なため、共有ライブラリー・コードが使用するすべてのネイティブ・ライブラリーのパスを、共有ライブラリー構成で指定することを検討します。
正しい WebSphere クラス・ローダーが、System.loadLibrary() を呼び出すクラスをロードすること、およびネイティブ・ライブラリーが「ネイティブ・ライブラリー・パス (Native library path)」設定で可視であることを確認します。
![[AIX HP-UX Solaris]](../images/unix.gif)
- System.mapLibraryName は間違ったライブラリー・ファイルを戻します。
- 共有ライブラリーをロードする場合、JVM は mapLibraryName(libName) を呼び出し、 libName をプラットフォーム固有の名前に変換します。AIX®、HP-UX または Solaris オペレーティング・システムでは、この呼び出しが、拡張子の間違っているファイル名 (例えば、libName.a のはずが libName.so になっているなど ) を戻す場合があります。この問題をデバッグするには、System.mapLibraryName() を呼び出すプログラムを作成し、それが正しいファイル名を戻すことを確認します。
- ネイティブ・ライブラリーが既にロードされています。
- この状態は、以下のエラーのうちのいずれかの結果で起こることがあります。
- ユーザー・エラー
- System.loadLibrary に対する複数の呼び出しをチェックし、余分な呼び出しを除去します。
- アプリケーション再始動時のエラー
- JVM には制限があり、ネイティブ・ライブラリーをロードできるのは、1 度に 1
つのクラス・ローダーのみです。
停止済みアプリケーションからガーベッジ・コレクターがクラス・ローダーをクリーンアップする前に
アプリケーションを再始動すると、エラーが発生します。
ネイティブ・ライブラリーをロードするクラスを移動する場合には、
そのネイティブ・ライブラリーに依存するすべてのクラスとそれらの依存関係も移動する必要があります。
このエラー状態を訂正するには、ネイティブ・ライブラリーのロードを、再ロードを行わないクラス・ローダーに移動します。以下の手順で移動してください。
- ネイティブ・ライブラリーをロードする、またはネイティブ・メソッドを保持するすべてのアプリケーション・クラスを、位置指定します。
- ステップ 1 のクラスの従属クラス (ロギング・パッケージなど) を識別します。
- サーバーに関連付けられた共有ライブラリーを作成するか、または個別の共有ライブラリーを作成します。
- ステップ 1 および 2 でクラス用にロードされた JAR ファイルを、アプリケーションから、ステップ 3 で作成した共有ライブラリーへ移動します。
- 変更を保存します。
- アプリケーションを再デプロイし、シナリオを再実行します。
サーバーを有効範囲としたライブラリー内のクラスは、 各サーバーのライフサイクルで一回ロードされます。 これにより、アプリケーションのライフサイクルにかかわらず、アプリケーションで必要なネイティブ・ライブラリーが Java 仮想マシンごとに必ず 1 回ロードされることになります。
- 従属したネイティブ・ライブラリー使用されました。
- 従属したネイティブ・ライブラリーが JVM クラス・ローダーによって検索またはロードされる必要があります。
つまり、ネイティブ・ライブラリー NL が別のネイティブ・ライブ
ラリー DNL に従属している場合、JVM クラス・ローダーは Java ライブラリー・パス上の DNL を検索する必要があります。これは、NL をロードする場合に JVM がネイティブ・コードを実行するためです。DNL への従属がある場合、JVM ネイティブ・コードは JVM クラス・ローダーを呼び出すだけで従属を解決することができます。
WebSphere クラス・ローダーが従属したネイティブ・ライブラリーをロードできません。
Java ライブラリー・パス (LIBPATH) を定義するプラットフォーム固有の環境変数を変更して、 未解決のネイティブ・ライブラリーを含むパスを組み込みます。