Days before, after the maintenance of the cluster, I met the NoClassDefFoundError when I tried to
resubmit the application to the yarn. At first, I thought that was caused by messing the classpath
up, or distribution of the application. After several try of re-compiling and re-distributing, I
found that the real cause is the failure of initialising an object
.
Later, I searched the NoClassDefFoundError, and the ClassNotFoundException came to me. These two exceptions are very frustrating.
ClassNotFoundException
ClassNotFoundException comes when you try to load a class at runtime by using Class.forName()
,
Classloader.loadClass()
or Classloader.findSystemClass()
explicitly and the requested class is
not present in classpath.
ClassNotFoundException is a checked Exception derived directly from java.lang.Exception
class.
Following is an example:
1
2
3
4
5
6
7
class A {
public static void main(String[] args){
Class B = Class.forName("xxx.B");
}
}
If there is no class file for xxx.B
in the class path, then a ClassNotFoundException
will be
thrown. Note that we load the class explicitly in this example.
NoClassDefFoundError
NoClassDefFoundError is a result of implicit loading of class because of a method call from that class or any variable access.
In case of NoClassDefFoundError, requested class was present at compile time but not available at runtime. Sometimes due to an exception during class initialization, e.g. exception from static block causes NoClassDefFoundError when a failed-to-load class was later referenced by the runtime.
NoClassDefFoundError is an Error derived from LinkageError
.
NoClassDefFoundError can also be caused due to multiple classloaders in J2EE environments. ClassLoader works on three principle delegation, visibility, and uniqueness. Delegation means every request to load a class is delegated to parent classloader, visibility means an ability to found classes loaded by the classloader, all child classloader can see classes loaded by parent classloader, but parent classloader can not see the class loaded by child classloaders. Uniqueness enforce that class loaded by the parent will never be reloaded by child classloaders. Now suppose if a class say User is present in both WAR file and EJB-JAR file and loaded by WAR classloader which is child classloader which loads the class from EJB-JAR. When a code in EJB-JAR refers to this User class, Classloader which loaded all EJB class doesn’t found that because it was loaded by WAR classloader which is a child of it.
This will result in java.lang.NoClassDefFoundError for User class. Also, If the class is present in both JAR file and you will call equals method to compare those two object, it will result in ClassCastException as object loaded by two different classloaders can not be equal.
Following is an example:
1
2
3
4
5
6
7
8
9
import xxx.B;
class A {
public static void main(String[] args){
B b = new B();
}
}
If there is no class file for xxx.B
in the class path, then a NoClassDefFoundError
will be
thrown, which is caused by a ClassNotFoundException
. Note that in this example we refer to
xxx.B
which cause the runtime to load the class implicitly.