gnu.util
Class ReloadableClassLoader

java.lang.Object
  extended by java.lang.ClassLoader
      extended by gnu.util.ReloadableClassLoader

public class ReloadableClassLoader
extends java.lang.ClassLoader

A neat hack to do class reloading.

Class reloading is, if not impossible and ugly, inconvenient in current class loader architecture. Sun should _really_ provide a standard way to do it. Many packages have implemented class reloading of their own, but none of them are cleanly designed to be reused IMHO. I ended up hacking my own version.

The problem of class reloading is that JVM does not provision the need. Once a class is loaded into JVM, it stays until some non-deterministic garbage collect time when no ones references a class anymore. However, JVM _does_ provide "namespace", to which different versions of the same class data can be loaded. A namespace is actually the "local scope" of an instance of a class loader. That is, a class can be loaded once and only once by the same intance of a class loader; but a new instance of a class loader can be created to load a new version of a class. Therefore, the trick of class reloading is to create a new instance of a class loader, and cache the loaded and reloaded classes in a global static place.

Note that dependent classes must be reloaded and resolved manually after the modified class is reloaded. For instance, given Class A and Class B (which depends on Class A) are loaded, and then Class A is modified and reloaded, Class B has to be reloaded to get the new version of Class A. It is because we can only force resolution of the new Class A for Class B through reloading Class B, as implied in The JavaTM Virtual Machine Specificatio.

Each of the following packages has its own reloadable class loader: BeanShell, GNU Server Pages, Jigsaw HTTPD, Resin's DynamicClassLoader, and Echidna multi-process system.

See Also:
bill's article, bill's book, Liang and Bracha

Field Summary
static java.util.Hashtable classes
           
static ReloadableClassLoader instance
           
static java.lang.Object INVALID
           
 
Constructor Summary
ReloadableClassLoader()
           
 
Method Summary
 java.lang.Class load(java.lang.String name, byte[] data, boolean resolve)
          Load class file data into namespace of this class loader.
 java.lang.Class loadClass(java.lang.String name, boolean resolve)
          Load class facility for JVM.
static byte[] read(java.io.File file)
          Read a class file.
static void reload_class(java.lang.String name, boolean resolve)
          Force loading a class.
static void reload_classes(java.lang.String[] wildnames, boolean resolve)
          Force loading a list of classes.
static void reload_package(java.lang.String name, boolean resolve)
          Force loading a package.
static void reload(java.util.Vector files, java.util.Vector names, boolean resolve)
          Force loading a list of classes into namespace of this class loader.
static void reset()
          There are several mysterious problems relating to VerifyError and LinkageError because of dependency and type-safety of reloading classes.
 
Methods inherited from class java.lang.ClassLoader
clearAssertionStatus, getParent, getResource, getResourceAsStream, getResources, getSystemClassLoader, getSystemResource, getSystemResourceAsStream, getSystemResources, loadClass, setClassAssertionStatus, setDefaultAssertionStatus, setPackageAssertionStatus
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

classes

public static java.util.Hashtable classes

instance

public static ReloadableClassLoader instance

INVALID

public static java.lang.Object INVALID
Constructor Detail

ReloadableClassLoader

public ReloadableClassLoader()
Method Detail

load

public java.lang.Class load(java.lang.String name,
                            byte[] data,
                            boolean resolve)
Load class file data into namespace of this class loader.

Parameters:
name - fully-qualified class name
data - raw bytes of class file

reload_class

public static void reload_class(java.lang.String name,
                                boolean resolve)
                         throws java.lang.ClassNotFoundException
Force loading a class. Consider using reload_classes(String[], boolean) for efficiency.

Throws:
java.lang.ClassNotFoundException
See Also:
reload_classes(String[], boolean)

reload_classes

public static void reload_classes(java.lang.String[] wildnames,
                                  boolean resolve)
                           throws java.lang.ClassNotFoundException
Force loading a list of classes.

Parameters:
wildnames - a list of wildnames; a wildname can be a class name to indicate a class to be reloaded, or a package name appended with ".*" to indicate a package to be reloaded
Throws:
java.lang.ClassNotFoundException

reload_package

public static void reload_package(java.lang.String name,
                                  boolean resolve)
                           throws java.lang.ClassNotFoundException
Force loading a package. Consider using reload_classes(String[], boolean) for efficiency.

Throws:
java.lang.ClassNotFoundException
See Also:
reload_classes(String[], boolean)

reload

public static void reload(java.util.Vector files,
                          java.util.Vector names,
                          boolean resolve)
                   throws java.lang.ClassNotFoundException
Force loading a list of classes into namespace of this class loader. If a class file is not found, exception will be thrown and classes in the rest of the list will not be loaded. Because each reloading creates a new instance of class loader (which will not be garbaged collected until all classes it loads are garbaged collected), requests of reloading should be grouped together (into longer vectors) instead of doing it separate. In particular, reload_classes(String[], boolean) should be used instead of reload_class(String, boolean) or reload_package(String, boolean) whenever possible.

Parameters:
names - fully-qualified class names
Throws:
java.lang.ClassNotFoundException

loadClass

public java.lang.Class loadClass(java.lang.String name,
                                 boolean resolve)
                          throws java.lang.ClassNotFoundException
Load class facility for JVM.

Overrides:
loadClass in class java.lang.ClassLoader
Throws:
java.lang.ClassNotFoundException

read

public static byte[] read(java.io.File file)
Read a class file.

Parameters:
name - fully-qualified class name
Returns:
raw bytes of class file, or null if class not found

reset

public static void reset()
There are several mysterious problems relating to VerifyError and LinkageError because of dependency and type-safety of reloading classes. I cannot understand the issue well enough to solve the problem. This method resets all caches and starts with a brand new classloader so as to trade caching for correctness.