NoClassDefFoundError on JFace FontRegistry

孤街浪徒 提交于 2019-12-06 02:13:35

I think the stacktrace presented above is concealing the real problem here. Below is the code in the method run within org.eclipse.jface.dialogs.ProgressMonitorDialog (with a comment added by me):

public void run(boolean fork, boolean cancelable,
         IRunnableWithProgress runnable) throws InvocationTargetException,
         InterruptedException {
     setCancelable(cancelable);
     try {
         aboutToRun();
         // Let the progress monitor know if they need to update in UI Thread
         progressMonitor.forked = fork;
         ModalContext.run(runnable, fork, getProgressMonitor(), getShell()
                 .getDisplay());
     } finally {
         finishedRun();  // this is line 498
     }
}

The second-from-bottom line in Jared's stacktrace is line 498 of this class, which is the call to finishedRun() within the finally block. I suspect that the real cause is an exception being thrown in the try block. Since the code in the finally block also throws an exception, the original exception is lost.

TofuBeer

It sounds like you are missing a JAR file that holds a dependency, as mentioned in this blog entry from July 2006, written by Sanjiv JIVAN:

Difference between ClassNotFoundException and NoClassDefFoundError

A ClassNotFoundException is thrown when the reported class is not found by the ClassLoader.
This typically means that the class is missing from the CLASSPATH.
It could also mean that the class in question is trying to be loaded from another class which was loaded in a parent ClassLoader and hence the class from the child ClassLoader is not visible.
This is sometimes the case when working in more complex environments like an App Server (WebSphere is infamous for such ClassLoader issues).

People often tend to confuse java.lang.NoClassDefFoundError with java.lang.ClassNotFoundException. However there's an important distinction.

For example an exception (an error really since java.lang.NoClassDefFoundError is a subclass of java.lang.Error) like

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

does not mean that the ActiveMQConnectionFactory class is not in the CLASSPATH.

In fact, its quite the opposite.

It means that the class ActiveMQConnectionFactory was found by the ClassLoader however when trying to load the class, it ran into an error reading the class definition.

This typically happens when the class in question has static blocks or members which use a Class that's not found by the ClassLoader.

So to find the culprit, view the source of the class in question (ActiveMQConnectionFactory in this case) and look for code using static blocks or static members.
If you don't have access the the source, then simply decompile it using JAD.

On examining the code, say you find a line of code like below, make sure that the class SomeClass in in your CLASSPATH.

private static SomeClass foo = new SomeClass();

Tip : To find out which jar a class belongs to, you can use the web site jarFinder. This allows you to specify a class name using wildcards and it searches for the class in its database of jars.
jarhoo allows you to do the same thing but its no longer free to use.

If you would like to locate the which jar a class belongs to in a local path, you can use a utility like jarscan. You just specify the class you'd like to locate and the root directory path where you'd like it to start searching for the class in jars and zip files.

To get a better handle on if it is a class loader issue go through the code where it works and add:

try
{
    final Class       clazz;
    final ClassLoader loader;

    clazz  = Class.forName("org/eclipse/jface/resource/FontRegistry");
    loader = clazz.getClassLoader(); 
    System.out.println("The classloader at step 1 is: " + loader);
}
catch(final Throwable ex)
{
    ex.printStackTrace();
}

And then do the same thing where you are getting the NoClassDefFoundError and see if the class loaders are different.

Then you will be able to ensure that it is the ClassLoader that is different. Can you report back with what happens with this? Depending on what the result is I might have more ideas.

VonC

To add to the excellent TofuBeer's answer, since NoClassDefFoundError indicates that:

  • class org.eclipse.jface.resource.FontRegistry was found by the ClassLoader,
  • but can not been loaded without triggering an error, like having static blocks or members which use a Class that's not found by the ClassLoader.

Let's look at org.eclipse.jface.resource.FontRegistry source code:

It does not have any static variable initialization (nor does its superclasses).

Let's look at org.eclipse.jface.resource.JFaceResources source code

The getFontRegistry() function in which the Error is triggered is using the static variable fontRegistry:

/**
 * The JFace font registry; <code>null</code> until lazily initialized or
 * explicitly set.
 */
private static FontRegistry fontRegistry = null;

Thus, it begs raises the question: why a static initialized variable would suddenly be considered null again ?

Because somehow FontRegistry or JFaceResources get unloaded by the gc ?!

If a field is declared static, there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. A static field, sometimes called a class variable, is incarnated when the class is initialized (§12.4).

So it doesn't matter whether instances of the class exist at any time, the field will exist as long as the Class itself has been loaded.


If this were a eclipse Plugin, this could have been related to this FAQ entry

Here is a typical scenario for a new user:
You are writing a plug-in that extends plug-in XYZ.
To get it to compile, you add a reference to the JAR file for plug-in XYZ to your project’s build path either from the Java Build Path property page or by editing the .classpath file.
When you launch a runtime workbench, the following surprising error is reported: java.lang.NoClassDefFoundError: XYZ.SomeClass.

Do not start looking in the Plug-ins and Fragments tab in the launch configuration for the runtime workbench.
That tab influences only which plug-ins are used for your runtime workbench and whether they are loaded from the workspace or from the Eclipse install directory.

Instead, start looking in the plug-in manifest.
Edit the plugin.xml file and ensure that XYZ is mentioned as a required plug-in.
Then, save the plugin.xml file.
This will update the project’s build path automatically.

Never manually edit the .classpath file when you are writing a plug-in.
The plug-in Manifest Editor simply overwrites any changes you make to it. Not very civilized, but that is the way it works.

If you try to load the class FontRegistry on your own (like TofoBeer described), you will find out that classes of the following JAR are dependent classes if using FontRegistry.

org.eclipse.core.commands_xxxxx.jar

You must add this JAR to your build path.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!