Loading Java classes in JVM properly to avoid ClassDefNotFound Exceptions

Date:18 September 2006
Product/Release:LANSA Integrator V11.0
Abstract:Important notes for using JAR files
Submitted By:LANSA Technical Support

Description:

If you encounter an error like ClassDefNotFound exception, then it means that the required class file is not found.

Suggestion:

You need to be careful where you put jar files. You could get ClassDefNotFound exceptions if you put a jar file in the ext directory. We recommend that you do not modify the iSeries default JDK configuration / settings (This JDK is shared by other applications). Use the /jsm/instance/system/SystemDefault.properties to change JDK startup values. Also do not put jar files in JDK directories. For example: /QIBM/UserData/Java400/ext directory.

A simple Java class model of just a unique package/class name is not 100% correct, you also have a further qualification of class loader.
{classloader} {package} {classname}

Regular Java applications running from command line involve three classloaders - Bootstrap, Extensions and System-Classpath classloaders, although it will appear as though there is only one classloader to the unsuspecting programmer. The three class loaders have a parent child relationship among themselves.

Bootstrap classloader is the parent of all classloaders and loads the standard JDK classes in lib directory of JRE (rt.jar and i18n.jar). All the java.* classes are loaded by this classloader.

Extensions Classloader is the immediate child of Bootstrap classloader. This classloader loads the classes in lib\ext directory of the JRE. For example, JDK1.4.x ships with its own implementation for JCE. The JCE implementation is identified by the sunjceprovider.jar and is present in JRE/lib/ext directory and is loaded by the extensions classloader.

System-Classpath classloader is the immediate child of Extensions classloader. It loads the classes and jars specified by the CLASSPATH environment variable, java.class.path system property, -cp or -classpath command line settings. If any of the jars specified in one of the above manner have a MANIFEST.MF file with a Class-Path attribute, the jars specified by the Class-Path attribute are also loaded.

http://download.oracle.com/javase/tutorial/ext/basics/load.html

The extension framework makes use of the class-loading delegation mechanism.

When the runtime environment needs to load a new class for an application, it looks for the class in the following locations, in order:

  1. Bootstrap classes: the runtime classes in rt.jar, internationalization classes in i18n.jar, and others.
     
  2. Installed extensions: classes in JAR files in the lib/ext directory of the JRE, and in the system-wide, platform-specific extension directory (such as /usr/jdk/packages/lib/ext on the SolarisTM Operating System, but note that use of this directory applies only to JavaTM 6 and later). 
     
  3. The class path: classes, including classes in JAR files, on paths specified by the system property java.class.path. If a JAR file on the class path has a manifest with the Class-Path attribute, JAR files specified by the Class-Path attribute will be searched also. By default, the java.class.path property's value is ., the current directory. You can change the value by using the -classpath or -cp command-line options, or setting the CLASSPATH environment variable. The command-line options override the setting of the CLASSPATH environment variable.

The precedence list tells you, for example, that the class path is searched only if a class to be loaded hasn't been found among the classes in rt.jar, i18n.jar or the installed extensions.

Unless your software instantiates its own class loaders for special purposes, you don't really need to know much more than to keep this precedence list in mind.

In particular, you should be aware of any class name conflicts that might be present.

For example, if you list a class on the class path, you'll get unexpected results if the runtime environment instead loads another class of the same name that it found in an installed extension.

The Java Class Loading Mechanism

The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.

Here are some highlights of the class-loading API:

  1. Constructors in java.lang.ClassLoader and its subclasses allow you to specify a parent when you instantiate a new class loader. If you don't explicitly specify a parent, the virtual machine's system class loader will be assigned as the default parent.
     
  2. The loadClass method in ClassLoader performs these tasks, in order, when called to load a class:
    1. If a class has already been loaded, it returns it.
    2. Otherwise, it delegates the search for the new class to the parent class loader.
    3. If the parent class loader does not find the class, loadClass calls the method findClass to find and load the class.
       
  3. The findClass method of ClassLoader searches for the class in the current class loader if the class wasn't found by the parent class loader. You will probably want to override this method when you instantiate a class loader subclass in your application.
     
  4. The class java.net.URLClassLoader serves as the basic class loader for extensions and other JAR files, overriding the findClass method of java.lang.ClassLoader to search one or more specified URLs for classes and resources.

To see a sample application that uses some of the API as it relates to JAR files, see the Using JAR-related APIs http://java.sun.com/docs/books/tutorial/deployment/jar/apiindex.html lesson in this tutorial.

Class Loading and the java Command

The Java platform's class-loading mechanism is reflected in the java command. In the java tool, the -classpath option is a shorthand way to set the java.class.path property. The -cp and -classpath options are equivalent.

Read full article - Internals of Java Class Loading at http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.html

Once a class is loaded into a JVM, the same class will not be loaded again. This leads to the question of what is meant by "the same class." Similar to the condition that an object has a specific state, an identity, and that an object is always associated with its code (class), a class loaded into a JVM also has a specific identity, which we'll look at now.

In Java, a class is identified by its fully qualified class name. The fully qualified class name consists of the package name and the class name. But a class is uniquely identified in a JVM using its fully qualified class name along with the instance of the ClassLoader that loaded the class. Thus, if a class named Cl in the package Pg is loaded by an instance kl1 of the class loader KlassLoader, the class instance of C1, i.e. C1.class is keyed in the JVM as (Cl, Pg, kl1). This means that the two class loader instances (Cl, Pg, kl1) and (Cl, Pg, kl2) are not one and the same, and classes loaded by them are also completely different and not type-compatible to each other.

How many class loader instances do we have in a JVM?

Class Loaders

In a JVM, each and every class is loaded by some instance of a java.lang.ClassLoader. The ClassLoader class is located in the java.lang package and developers are free to subclass it to add their own functionality to class loading. Whenever a new JVM is started by typing java MyMainClass, the "bootstrap class loader" is responsible for loading key Java classes like java.lang.Object and other runtime code into memory first. 

The runtime classes are packaged inside of the JRE\lib\rt.jar file. We cannot find the details of the bootstrap class loader in the Java documentation, since this is a native implementation. For the same reason, the behavior of the bootstrap class loader will also differ across JVMs.

In a related note, we will get null if we try to get the class loader of a core Java runtime class, like this:

log(java.lang.String.class.getClassLoader());

Java extension class loader

We can store extension libraries, those that provide features that go beyond the core Java runtime code, in the path given by the java.ext.dirs property. The ExtClassLoader is responsible for loading all .jar files kept in the java.ext.dirs path. A developer can add his or her own application .jar files or whatever libraries he or she might need to add to the classpath to this extension directory so that they will be loaded by the extension class loader.

AppClassLoader

The third and most important class loader from the developer perspective is the AppClassLoader. The application class loader is responsible for loading all of the classes kept in the path corresponding to the java.class.path system property.