So I have a classloader (MyClassLoader) that maintains a set of "special" classes in memory. These special classes are dynamically compiled and stored in a byte array inside MyClassLoader. When the MyClassLoader is asked for a class, it first checks if its specialClasses
dictionary contains it, before delegating to the System classloader. It looks something like this:
class MyClassLoader extends ClassLoader {
Map<String, byte[]> specialClasses;
public MyClassLoader(Map<String, byte[]> sb) {
this.specialClasses = sb;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (specialClasses.containsKey(name)) return findClass(name);
else return super.loadClass(name);
}
@Override
public Class findClass(String name) {
byte[] b = specialClasses.get(name);
return defineClass(name, b, 0, b.length);
}
}
If I want to perform transformations (e.g. instrumentation) on the specialClasses
, I can do so simply by modifying the byte[]
before i call defineClass()
on it.
I would also like to transform the classes which are provided by the System classloader, but the System classloader doesn't seem to provide any way of accessing the raw byte[]
of the classes it provides, and gives me the Class
objects directly.
I could use a -javaagent
instrument all classes loaded into the JVM, but that would add overhead to the classes which I do not want to instrument; I only really want the classes loaded by MyClassLoader to be instrumented.
- Is there any way of retrieving the raw
byte[]
of the classes provided by the parent classloader, so I can instrument them before defining my own copy? - Alternately, is there any way of emulating the functionality of the System classloader, in terms of where it grabs it's
byte[]
s from, so that MyClassLoader can instrument and define its own copy of all the System classes (Object, String, etc.)?
EDIT:
So I tried another approach:
- Using a
-javaagent
, Capture thebyte[]
of every class that is loaded and store it in a hashtable, keyed by the name of the class. - MyClassLoader, instead of delegating the system classes to its parent classloader, would instead load their bytecode from this hashtable using the class name and define it
In theory this would let MyClassLoader define its own version of the system classes with instrumentation. However, it fails with a
java.lang.SecurityException: Prohibited package name: java.lang
Clearly the JVM does not like me defining the java.lang
classes myself, even though it should (in theory) be from the same byte[]
source that the bootstrap-loaded classes should come from. The search for a solution continues.
EDIT2:
I found a (really sketchy) solution for this problem, but if someone who knows more than me about the intricacies of the Java classloading/instrumentation can come up with something less sketchy, that would be awesome.