I’m using this method to read back the byte[] representation of loaded classes.
(for read-only instrumentation requirements, not to actually modify)
The reason I need the in-memory representations (rather than simply grabbing them from the classpath) is 2-fold:
- some of them will have already been instrumented
- some of them are defined at run-time, so do not exist in the classpath.
However the javadoc on the method is rather lacking on implementation details.
The Oracle VM certainly executes it synchronously, which means this, while conceptually horrible, works fine:
private byte[] classBytes;
/**
* Reads back from the JVM the byte[] representation of an already loaded class
*
* @param className
* The name of the class to read back.
* @param cl
* The class loader used to load the class.
* @return
*/
synchronized byte[] getClassBytes(String className, ClassLoader cl) {
try {
// trigger a retransformation (that will store the class's bytes in
// classBytes[]
inst.retransformClasses(cl.loadClass(className));
byte[] classBytes = this.classBytes;
this.classBytes = null;
return classBytes;
} catch (ClassNotFoundException | UnmodifiableClassException e) {
throw new RuntimeException("Failed reading back class bytes from the JVM", e);
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (classBeingRedefined != null) {
// this will only be reachable immediately after an invocation of
// getClassBytes.
// fingers crossed all implementations execute this synchronously.
// Oracle's VM certainly does, but the method that causes the call
// (Instrumentation#retransformClasses)
// is not very explicit on exactly how it's implemented.
System.out.println("byte[] read-back for " + className);
classBytes = classfileBuffer.clone();
return null;
}
//<snip>
}