(Eclipse 起動プロファイルを介して) SWT アプリケーションを起動すると、次のスタック トレースが表示されます。
Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/jface/resource/FontRegistry
at org.eclipse.jface.resource.JFaceResources.getFontRegistry(JFaceResources.java:338)
at org.eclipse.jface.window.Window.close(Window.java:313)
at org.eclipse.jface.dialogs.Dialog.close(Dialog.java:971)
at org.eclipse.jface.dialogs.ProgressMonitorDialog.close(ProgressMonitorDialog.java:348)
at org.eclipse.jface.dialogs.ProgressMonitorDialog.finishedRun(ProgressMonitorDialog.java:582)
at org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:498)
at com.blah.si.workflow.SWTApplication.main(SWTApplication.java:135)
さて、これを奇妙にするもの:
- プロジェクトのビルド パスを変更し、jface.jar をソース プロジェクト (同じバージョン - 3.3.1) に置き換えると、エラーはなくなります。
- 同じ jar を使用する他のアプリケーション、および同じ起動プロファイルとプロジェクトのコピーはすべて正常に動作します。
- これは ではありません
ClassNotFoundException
。クラスはクラスパスにあります。ソースを jar に添付すると、getFontRegistry メソッドにデバッグできます。このメソッドは、最終的NoClassDefFoundError
に行 338 で をスローする前に、数回正常に実行されます。行 337 は、静的変数が初期化されているかどうかを確認する「if variable == null」ステートメントです。まだ初期化されていない場合、338行目で初期化しています。最初は null チェックに失敗し、初期化が実行されます。その後のメソッドのパスでは、null チェックがパスするため、既に初期化されている静的な値が返されます。最終パス (失敗したパス) で、(静的変数が既に初期化されていても) null チェックが再び失敗し、静的変数を再初期化しようとすると、NoClassDefFoundError
投げられます。関連するソースは次のとおりです (336 行目以降、fontRegistry はプライベートな静的変数であり、他の場所では設定されていないことに注意してください)。
.
public static FontRegistry getFontRegistry() {
if (fontRegistry == null) {
fontRegistry = new FontRegistry(
"org.eclipse.jface.resource.jfacefonts");
}
return fontRegistry;
}
.
- jar の新しいコピーを既に取得しており (破損していないことを確認するため)、.classpath ファイルと .project ファイルを削除し、新しいプロジェクトを開始して、起動プロファイルを再作成しました。変化なし。
上記の #3 の特殊性のため、ある種の奇妙なクラスローダの動作を疑っています。メソッドを通過する最後のパスが別のクラスローダにあるかのように見えますか?
アイデア?
更新: Pourquoi Litytestdata によって提供された回答により、ProgressMonitorDialog の 458 行目のすぐ上の try ブロックで何が起こるかに注意を払うようになりました。実際、そのコードは例外をスローしていましたが、それは finally ブロックによって飲み込まれていました。根本的な原因は、別のクラスの欠落でした (欠落しているクラスは、JFontRegistry またはそれに直接関連するクラスではなく、エッジ ケースで依存するクモの巣でした)。 、それが突破口だったので、Pourquoi'sを受け入れました。ありがとうございます。