Suppose we want to use the ASM invocations to produce the very simple class:
public class Chocalate {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("helloworld");
}
}
It is basically a two-step task.
First step: use the bytecode plugin to view what asm code should be produced for such java code.
Second step, package the asm code and run them using the classloader:
add these code to the bottom of the dump() method. Dump returns the bytecode sequence for a class, it can be directly written into a class file using the FileOutputStream.
Also, we can directly use the class without storing it to the disk as follows.
byte[] code =cw.toByteArray();;
ChocalateDump loader = new ChocalateDump();// the class extends the Classloader, so that we can use the "protected" defineClass method to load the class just generated.
Class<?> exampleClass = loader.defineClass("Chocalate", code, 0, code.length);// load the class
exampleClass.getMethods()[0].invoke(null, new Object[] { null });
// this uses the reflection to invoke the main method.
That is all, the console will print "helloworld" as what the original Chocalate class did.
From the above process, we know we can generate asm code even without understanding the very details inside. All we need to is write an equivalent java code and ask plugin for the proper asm invocations.
For completeness, I also attach the ChocalateDump, i.e., the class containing the ASM invocations.
import java.util.*;
import org.objectweb.asm.*;
import org.objectweb.asm.attrs.*;
public class ChocalateDump extends ClassLoader implements Opcodes {
public static void main(final String args[]) throws Exception {
dump();
}
public static byte[] dump () throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Chocalate", null, "java/lang/Object", null);
cw.visitSource("Chocalate.java", null);
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(2, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitInsn(RETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "LChocalate;", null, l0, l1, 0);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(9, l0);
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("helloworld");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(10, l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLocalVariable("args", "[Ljava/lang/String;", null, l0, l2, 0);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
cw.visitEnd();
byte[] code =cw.toByteArray();;
ChocalateDump loader = new ChocalateDump();
Class<?> exampleClass = loader.defineClass("Chocalate", code, 0, code.length);
exampleClass.getMethods()[0].invoke(null, new Object[] { null });
return cw.toByteArray();
}
}