A fluent interface API in Java language which is used to write jvm assembly directly.
It's simple, after you are already familiar with jvm byte code...
Your hello world example would be:
ClsBuilder b = new ClsBuilder(Opcodes.V1_6, Opcodes.ACC_PUBLIC, "test/TestGenCls", null, "java/lang/Object", null, ClassWriter.COMPUTE_FRAMES);
MethodBuilder c = b.newMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null, 0, 0);
c.aload_0();
c.invokespecial("java/lang/Object", "<init>", "()V");
c.return_();
MethodBuilder main = b.newMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null, 0, 0);
main.getstatic("java/lang/System", "out", "Ljava/io/PrintStream;");
main.ldc("Hello World!");
main.invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V");
main.return_();
byte[] bytes = b.toByteArray();
Class<?> cls = ClassLoadingUtil.loadClsInstantly("test.TestGenCls", bytes);
Method m = cls.getMethod("main", String[].class);
m.invoke(null, new Object[] { new String[0] });
assertTrue(true);// this program should print out 'Hello world!'
You can save the generated bytes to a file and examine it using javap:
$ javap -c TestGenCls -verbose
public class test.TestGenCls extends java.lang.Object
minor version: 0
major version: 50
Constant pool:
const #1 = Asciz test/TestGenCls;
const #2 = class #1; // test/TestGenCls
const #3 = Asciz java/lang/Object;
const #4 = class #3; // java/lang/Object
const #5 = Asciz <init>;
const #6 = Asciz ()V;
const #7 = NameAndType #5:#6;// "<init>":()V
const #8 = Method #4.#7; // java/lang/Object."<init>":()V
const #9 = Asciz main;
const #10 = Asciz ([Ljava/lang/String;)V;
const #11 = Asciz java/lang/System;
const #12 = class #11; // java/lang/System
const #13 = Asciz out;
const #14 = Asciz Ljava/io/PrintStream;;
const #15 = NameAndType #13:#14;// out:Ljava/io/PrintStream;
const #16 = Field #12.#15; // java/lang/System.out:Ljava/io/PrintStream;
const #17 = Asciz Hello World!;
const #18 = String #17; // Hello World!
const #19 = Asciz java/io/PrintStream;
const #20 = class #19; // java/io/PrintStream
const #21 = Asciz println;
const #22 = Asciz (Ljava/lang/String;)V;
const #23 = NameAndType #21:#22;// println:(Ljava/lang/String;)V
const #24 = Method #20.#23; // java/io/PrintStream.println:(Ljava/lang/String;)V
const #25 = Asciz Code;
{
public test.TestGenCls();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #18; //String Hello World!
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
Ok, that's almost all, may be this is an interesting way to write bytecode directly, have fun!
Oh, after all, it's based on ASM 4, btw...