When I launch an SWT application (via an Eclipse launch profile), I receive the following stack trace:
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)
Now, the things that make this odd:
- When I change the project build path and replace jface.jar with the source project (same version - 3.3.1), the error goes away.
- Other applications I have that use the same jar, and a copy of the same launch profile and project, all works fine.
- This is NOT a
ClassNotFoundException
. The class is on the classpath. If I attach source to the jar, I can debug into the getFontRegistry method. The method will execute successfully several times before eventually throwing aNoClassDefFoundError
on line 338. Line 337 is a "if variable == null" statement checking to see if a static variable has been initialized. Line 338 is initializing it if it is not already initialized. The first time through, the null check fails, and the initialization is performed. On subsequent passes through the method, the null check passes, and thus the already-initialized static value is returned. On the final pass (the one that fails,) the null check fails again (even though the static variable has already been initialized) and when it tries to re-initialize the static variable, theNoClassDefFoundError
is thrown. Here is the relevant source (starting with line 336, note that fontRegistry is a private static variable that is set in no other place):
.
public static FontRegistry getFontRegistry() {
if (fontRegistry == null) {
fontRegistry = new FontRegistry(
"org.eclipse.jface.resource.jfacefonts");
}
return fontRegistry;
}
.
- I have already gotten a fresh copy of the jar (to ensure it isn't corrupted,) deleted my .classpath and .project files and started a fresh project, and recreated the launch profile. No change.
Because of the peculiarities in #3 above, I'm suspecting some kind of wierd classloader behavior - it seems as if that final pass through the method is in another classloader?
Ideas?
Update: The answer provided by Pourquoi Litytestdata prompted me to pay attention to what happens in the try block just above line 458 of ProgressMonitorDialog. Indeed, that code was throwing an exception, which was being gobbled by the finally block. The root cause was ANOTHER missing class (the missing class was not JFontRegistry or any of its directly related classes, but another that was spider-web dependencied in an edge case.) I'm upvoting all answers pointing me to pay attention to the classpath, and accepting Pourquoi's, because it was the breakthrough. Thanks to all.