I'm implementing a feature that requires passing dynamically generated types (in binary representation, serialised with Kryo) between several instances of JVM (over the network). In order to properly resolve what types are loaded and what are not I use a custom system class loader (passed as java -Djava.system.class.loader
parameter), which is used by other dynamically created class loaders as a parent. This custom system class loader knows of its children and in case it cannot find a class these derived class loaders can be asked if they have it (this is a reverse to the standard hierarchical structure of class loaders).
These dynamically generated types get transferred and loaded between different JVMs perfectly fine. The problem arises when I try to deserialise an instance of some type (a corresponding class is loaded from disc and is identical for all JMVs) that references one of the dynamically generated types -- ClassNotFoundException is raised by an instance of Kryo, which tries to readClass
by name of the dynamically generated type.
Inside method readClass
there a call to Class.forName
, which in turn does not use the specified custom class loader (that knows of all dynamically generated types) and instead uses sun.misc.Launcher$AppClassLoader instance.
Is it possible to specify a custom system-wide class loader, so that all classes are loaded with it in order to avoid the described problem?
Update
Further analysis revealed that ClassLoader.getSystemClassLoader()
actually returns the specified custom system class loader. Fortunately, the Kryo library supports setting of a custom class loader specifically for loading classes upon deserialisation. These two facts formed the basis of a solution to the described problem.
How would you load the custom class loader if all classes have to laoded using that class loader?
One way to get around this is to create a native instrumentation agent. This is loaded before any classes are loaded.
Another way around it is to compile your own version of AppClassLoader and prefix it to the boot class path or add it to the libs/endorsed
directory.