Last Updated: February 25, 2016
·
4.351K
· eller86

Generate class dynamically with ObjectWeb ASM

At first, you have to create byte array (= contents in .class file) with ClassWriter.

private byte[] createClassBinary() {
    ClassWriter cw = new ClassWriter(0);
    cw.visit(V1_5, ACC_PUBLIC, "pkg/OwnClass", null, "java/lang/Object", null);
    {
        // constructor
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitMaxs(2, 1);
        mv.visitVarInsn(ALOAD, 0); // push `this` to the operand stack
        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V"); // call the constructor of super class
        mv.visitInsn(RETURN);
        mv.visitEnd();
    }
    {
        // public Object get() { return new Object(); }
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "()Ljava/lang/Object;", null, null);
        mv.visitMaxs(2, 1);
        mv.visitTypeInsn(NEW, Type.getInternalName(Object.class));
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V");
        mv.visitInsn(ARETURN);
        mv.visitEnd();
    }
    cw.visitEnd();
    return cw.toByteArray();
}

Then, you can create Class instance from this byte array. You have to create original Class loader and call its #defineClass method.

private static class OwnClassLoader extends ClassLoader {
    public Class<?> defineClass(String name, byte[] b) {
        return defineClass(name, b, 0, b.length);
    }
}

private Class<?> createClass(byte[] b) {
    return new OwnClassLoader().defineClass("pkg.OwnClass", b);
}