I read a class' methods and their contents using the ASM library for Java ByteCode. This is to output any method's local variables names in the class:
ClassReader reader = new ClassReader(new FileInputStream(new File("TheClass.class")));
final ClassNode classNode = new ClassNode();
reader.accept(classNode, 0);
for (final MethodNode mn : (List<MethodNode>)classNode.methods) {
for (LocalVariableNode n : (List<LocalVariableNode>)mn.localVariables) {
System.out.println(n.name);
}
}
And this is the source of the compiled TheClass
class file:
public class TheClass {
public final String a;
public final String b;
public TheClass(String c, String d) {
this.b = d;
this.a = c;
}
}
So the output is, logically, this
, c
, d
. Now, I need to copy this compiled class into a new file, but change the <init>
method's parameters (local variables) to different names (e
, f
). How can I do so? I have little to no experience with MethodVisitors and such.
You'll need to write an adapter (a subclass of ClassVisitor
) and chain it with reader
. For instance,
ClassReader reader = new ClassReader(new FileInputStream(new File("TheClass")));
ClassWriter writer = new ClassWriter(reader, 0);
TraceClassVisitor printer = new TraceClassVisitor(writer,
new PrintWriter(System.getProperty("java.io.tmpdir")
+ File.separator + name + ".log"));
ClassAdapter adapter = new ClassAdapter(printer);
reader.accept(adapter, 0);
byte[] b = writer.toByteArray();
With it you'll get byte[]
, which you can save into file, or load into Class
with a ClassLoader
.
(TraceClassVisitor
is just another ClassVisitor
that I chain it also to get a human-readable log in your temp directory.)
The adapter could look like the following. The method you'll want to override is visitLocalVariable
:
public class ClassAdapter extends ClassVisitor {
public ClassAdapter(ClassVisitor cv) {
super(Opcodes.ASM5, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
return new MethodAdapter(mv);
}
}
public class MethodAdapter extends MethodVisitor {
public MethodAdapter(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
// Put your rename logic here
if (name.equals("c"))
name = "e";
else if (name.equals("d"))
name = "f";
super.visitLocalVariable(name, desc, signature, start, end, index);
}
}