ASM(位元組碼處理工具)
阿新 • • 發佈:2019-02-15
import java.io.FileOutputStream; import java.io.PrintStream; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; /** * @author Eric Bruneton */ public class Helloworld extends ClassLoader implements Opcodes { public static void main(String args[]) throws Exception { // 生成如下類檔案 // public class Example { // public static void main (String[] args) { // System.out.println("Hello world!"); // } // } // 為Example提供ClassWriter,要求Example繼承自Object ClassWriter cw = new ClassWriter(0); cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); // 為隱含的預設構造器建立MethodWriter MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); // 將this變數放入區域性變量表 mw.visitVarInsn(ALOAD, 0); // 呼叫父類的預設建構函式 mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V",false); mw.visitInsn(RETURN); // 這段程式碼使用了最大為1的棧元素,且只有一個區域性變數 mw.visitMaxs(1, 1); mw.visitEnd(); // 為main方法建立MethodWriter mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); // 將System的out域入棧 mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); // String型別的"Hello World!"常量入棧 mw.visitLdcInsn("Hello world!"); // 呼叫System.out的println方法 mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); mw.visitInsn(RETURN); // 這段程式碼使用了最大為2的棧元素,包含兩個區域性變數 mw.visitMaxs(2, 2); mw.visitEnd(); // 獲得Example類的位元組碼,並且動態載入它 byte[] code = cw.toByteArray(); FileOutputStream fos = new FileOutputStream("Example.class"); fos.write(code); fos.close(); Helloworld loader = new Helloworld(); Class<?> exampleClass = loader.defineClass("Example", code, 0, code.length); // 使用動態生成的類列印'Helloworld' exampleClass.getMethods()[0].invoke(null, new Object[] { null }); // ------------------------------------------------------------------------ // 使用GeneratorAdapter的示例(很方便但是更慢) // ------------------------------------------------------------------------ cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); // 為隱含的預設構造器建立GeneratorAdapter Method m = Method.getMethod("void <init> ()"); GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); mg.loadThis(); mg.invokeConstructor(Type.getType(Object.class), m); mg.returnValue(); mg.endMethod(); // 為main方法建立GeneratorAdapter m = Method.getMethod("void main (String[])"); mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); mg.push("Hello world!"); mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); mg.returnValue(); mg.endMethod(); cw.visitEnd(); code = cw.toByteArray(); loader = new Helloworld(); exampleClass = loader.defineClass("Example", code, 0, code.length); // 使用動態生成的類列印'Helloworld' exampleClass.getMethods()[0].invoke(null, new Object[] { null }); } }