Reputation: 30301
Suppose in my JVM I have a loaded class Class<C> myClass
. Is there a reliable way to ask the JVM for the bytecode contents of the .class? I.e. something like this:
<C> byte[] getClassBytecode(Class<C> myClass) {
return /* the contents of the .class resource where C was loaded from */;
}
(obviously an InputStream
would be as good as the byte[]
). I know I can use myClass.getResource()
(and friends) to fetch the class file, but hammering on the class name to get an URL to feed to getResource feels wrong. Also, I am not sure how this would behave in case C
was dynamically generated (e.g. using javax.tools.JavaCompiler
).
Any (better) idea?
note: the goal is to be able to push the bytecode classes to a different JVM and use a custom classloader to load them there
Upvotes: 15
Views: 13452
Reputation: 2097
You can use ASM library to get the detail bytecode of a class. A sample code is below.
public class AAA extends ClassLoader{
public static void main(){
String resource = caller.replace('.', '/')+".class";
InputStream is = getResourceAsStream(resource);
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor visitor = new BCMerge(Opcodes.ASM5, cw, callee);
cr.accept(visitor, 0);
}
}
class BCMerge extends ClassVisitor{
public MethodVisitor visitMethod(int access, String name, String desc,String signature, String[] exceptions) {
System.out.println(name);
if (cv != null) {
return new MyMethodVisit(cv.visitMethod(access, name, desc, signature, exceptions));
}
return null;
}
}
public class MyMethodVisit extends MethodVisitor{
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
System.out.println("opcode:" + opcode + " owner:" + owner + " name:"+ name + " desc:" + desc);
return super.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
Upvotes: 4
Reputation: 296
note: the goal is to be able to load the bytecode using a custom classloader on a different JVM
A classloader doesn't just load bytecode. Therefore, if you were able to get the bytecode out of the JVM memory (which is theoretically possible if you write a lot of implementation-specific native code), it would be useless to your remote classloader. You need to give it an actual .class
file.
And Class.getResource() is the best way to accomplish this task. Since it looks in the same package as the invoking class, all you need to do is take the class' simple name, append ".class" and you're done.
It does become a little more difficult if you have inner or nested classes, but that's an implementation detail that you'll have to deal with regardless (if you push the initial class, you'll still need to pull any dependent classes).
Upvotes: 11