Thursday, November 7, 2013

Java Throwable: ClassNotFoundException vs. NoClassDefFoundError

Many times we have confused ourselves with the following two Java Throwable messages:

Although both of them are related to Java Classpath,[7] they are different.[1] In a nutshell, they differ in this way:
  • ClassNotFoundException
    • Thrown when an application tries to load a class at run-time and name was provided during runtime not at compile time
  • NoClassDefFoundError[11,12]
    • When JVM or a ClassLoader instance is not able to find a particular class at runtime which was available during compile time

ClassNotFoundException


ClassNotFoundException is thrown when an application tries to load in a class through its string name using:
  • The forName method in class Class.
  • The findSystemClass method in class ClassLoader .
  • The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found. See How-To section below for solutions.

NoClassDefFoundError


The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found. One way to debug NoClassDefFoundError is going back to the design-time environment. Using an IDE, you might be able to find where the class is coming from at compile time. Then use that as a clue to find why that class cannot be found at runtime. See How-To section for more details.

What Could Go Wrong?


Classpath[7] in Java is path to directory or list of directory which is used by ClassLoaders[3] to find and load class in Java program. If a class cannot be found at runtime, it may be due to:
  • Classloaders are not set up correctly[3]
  • Class is corrupted
    • Java compiler is not backwards compatible. For example, bytecode generated with JDK 7 won't run in Java 1.6 JVM.[2]
  • Jar file could be renamed in the runtime environment
  • Your startup script may have overridden Classpath environment variable
  • You might be running your program using jar command and class was not defined in manifest file's ClassPath attribute.

How to Resolve it?


The application that triggered the request to load a class receives a ClassNotFoundException or NoClassDefFoundError if neither the classloader nor any of its ancestors can locate the class.[3] In that case, you can take the following actions:
  • You can use System.getproperty("java.class.path") to get the class path used by your Java application at runtime.[4]
  • Try to run with -classpath option using the classpath you think would work: if it works, then it's a sign that some one is overriding java classpath.
  • Check the permission of your jar files.  Your application may not be able to access them.
  • Enable class loading traces at JVM level. For example, you can specify -verbose:class for both JRockit and HotSpot.[5]
  • If your application is deployed in WebLogic server, read [3] and enable classloader debugging. 
    •  For example, you may want to set:
      • -Dweblogic.utils.classloaders.GenericClassLoader.Verbose=true 
      • -Dweblogic.utils.classloaders.ChangeAwareClassLoader.Verbose=true
    • You can also use Classloader Analysis Tool (http://localhost:port/wls-cat/) which is deployed by default on admin servers of domains in development mode.[6]
    • If your application runs in one environment and not in another,
      • Try adding the CLASSPATH explicitly pointing to your jars in setDomainEnv script 
      • You can also set "EXT_PRE_CLASSPATH=...." or "EXT_POST_CLASSPATH=..." where "..." are your jar files. The setDomainEnv.sh will pick up these and add to CLASSPATH. The above environment variables can be set when you log on or somewhere at the top of setDomainEnv.sh.



References

  1. 3 ways to solve java.lang.NoClassDefFoundError in Java J2EE
  2. Is JDK “upward” or “backward” compatible?
  3. WebLogic's Classloading Framework (Xml and More)
  4. System Properties
  5. -verbose:class Option
  6. Using the new WebLogic Classloader Analysis Tool (CAT)
    • Note that I'm not sure if this is still available in newer WLS releases.
  7. How to Set Classpath for Java on Windows Unix and Linux
    • Main difference between PATH and CLASSPATH is that former is used to locate Java commands while later is used to locate Java class files.
  8. java.lang.UnsatisfiedLinkError: Setting Environment Variable (Xml and More)
  9. Using the Classloader Analysis Tool (CAT)
  10. WebLogic Server (WLS) Support Pattern: Investigating Different Classloading Issues (Doc ID 1572862.1)
  11. If you use JPA 2.1 with WLS 12.1.1 or 12.1.2, then you may see this (because JPA 2.1 only supported starting in 12.1.3):
    • java.lang.NoClassDefFoundError: javax/persistence/StoredProcedureQuery
  12. java.lang.NoClassDefFoundError: sun/io/CharacterEncoding (Xml and More)


No comments: