ASMPrint类
下面是ASMPrint类的代码,它是利用org.objectweb.asm.util.TraceClassVisitor类来实现的。在使用的时候,我们注意修改一下className、parsingOptions和asmCode参数就可以了。
import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.util.ASMifier; import jdk.internal.org.objectweb.asm.util.Printer; import jdk.internal.org.objectweb.asm.util.Textifier; import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; import java.io.IOException; import java.io.PrintWriter; public class ASMPrint { public static void main(String[] args) throws IOException { // (1) 设置参数 String className = "sample.HelloWorld"; int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG; boolean asmCode = true; // (2) 打印结果 Printer printer = asmCode ? new ASMifier() : new Textifier(); PrintWriter printWriter = new PrintWriter(System.out, true); TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter); new ClassReader(className).accept(traceClassVisitor, parsingOptions); } }
在现在阶段,我们主要是使用这个类,来帮助我们生成ASM代码;
ASMPrint类使用示例
假如,有如下一个HelloWorld类:
public class HelloWorld { public void test() { System.out.println("Test Method"); } }
对于ASMPrint类来说,其中
- className值设置为类的全限定名,可以是我们自己写的类,例如sample.HelloWorld,也可以是JDK自带的类,例如java.lang.Comparable。
- asmCode值设置为true或false。如果是true,可以打印出对应的ASM代码;如果是false,可以打印出方法对应的Instruction。
- parsingOptions值设置为ClassReader.SKIP_CODE、ClassReader.SKIP_DEBUG、ClassReader.SKIP_FRAMES、ClassReader.EXPAND_FRAMES的组合值,也可以设置为0,可以打印出详细程度不同的信息。
运行结果示例:
package asm.sample; import java.util.*; import jdk.internal.org.objectweb.asm.*; public class HelloWorldDump implements Opcodes { public static byte[] dump () throws Exception { ClassWriter cw = new ClassWriter(0); FieldVisitor fv; MethodVisitor mv; AnnotationVisitor av0; cw.visit(52, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld", null, "java/lang/Object", new String[] { "java/lang/Cloneable" }); { fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, "intValue", "I", null, new Integer(10)); fv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null); mv.visitCode(); mv.visitInsn(ICONST_1); mv.visitVarInsn(ISTORE, 1); mv.visitInsn(ICONST_2); mv.visitVarInsn(ISTORE, 2); mv.visitVarInsn(ILOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitInsn(IADD); mv.visitVarInsn(ISTORE, 3); mv.visitInsn(RETURN); mv.visitMaxs(2, 4); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); mv.visitParameter("args", 0); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn("HelloWorld"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); mv.visitInsn(RETURN); mv.visitMaxs(2, 1); mv.visitEnd(); } cw.visitEnd(); return cw.toByteArray(); } }
粘贴到Android studio会自动排版。
类似工具:
public class PrintASMCodeCore { public static void main(String[] args) throws Exception { readClass(ServiceProvider.class.getName()); } /** * @param className 接受.分割符分割的类名 */ private static void readClass(String className) throws IOException { // (1) 设置参数 int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG; // (2) 打印结果 Printer printer = new ASMifier(); PrintWriter printWriter = new PrintWriter(System.out, true); TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter); new ClassReader(className).accept(traceClassVisitor, parsingOptions); } }
其他相关工具类
PrintASMCodeCore.java
package run; import org.objectweb.asm.ClassReader; import org.objectweb.asm.util.ASMifier; import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.TraceClassVisitor; import java.io.IOException; import java.io.PrintWriter; /** * Print asm core code. * * @see ASMPrint * @see PrintASMCodeTree * @see PrintASMTextClass * @see PrintASMTextLambda */ public class PrintASMCodeCore { public static void main(String[] args) throws IOException { // (1) 设置参数 String className = "sample.HelloWorld"; int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG; // (2) 打印结果 Printer printer = new ASMifier(); PrintWriter printWriter = new PrintWriter(System.out, true); TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter); new ClassReader(className).accept(traceClassVisitor, parsingOptions); } }
PrintASMCodeTree.java
package run; import lsieun.asm.util.TreePrinter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.TraceClassVisitor; import java.io.IOException; import java.io.PrintWriter; /** * Print asm tree code. * * @see ASMPrint * @see PrintASMCodeCore * @see PrintASMTextClass * @see PrintASMTextLambda */ public class PrintASMCodeTree { public static void main(String[] args) throws IOException { // (1) 设置参数 String className = "sample.HelloWorld"; int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG; // (2) 打印结果 Printer printer = new TreePrinter(); PrintWriter printWriter = new PrintWriter(System.out, true); TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter); new ClassReader(className).accept(traceClassVisitor, parsingOptions); } }
PrintASMTextClass.java
package run; import org.objectweb.asm.ClassReader; import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceClassVisitor; import java.io.IOException; import java.io.PrintWriter; /** * @see ASMPrint * @see PrintASMCodeCore * @see PrintASMCodeTree * @see PrintASMTextLambda */ public class PrintASMTextClass { public static void main(String[] args) throws IOException { // (1) 设置参数 String className = "sample.HelloWorld"; int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG; // (2) 打印结果 Printer printer = new Textifier(); PrintWriter printWriter = new PrintWriter(System.out, true); TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter); new ClassReader(className).accept(traceClassVisitor, parsingOptions); } }
PrintASMTextLambda.java
package run; import lsieun.utils.StringUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceClassVisitor; import java.io.IOException; import java.io.PrintWriter; /** * Print Lambda anonymous inner class. * * @see ASMPrint * @see PrintASMCodeCore * @see PrintASMCodeTree * @see PrintASMTextClass */ public class PrintASMTextLambda { public static void main(String[] args) throws IOException { // (1) 设置参数 String str = "[-54, -2, -70, -66, ...]"; byte[] bytes = StringUtils.array2Bytes(str); int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG; // (2) 打印结果 Printer printer = new Textifier(); PrintWriter printWriter = new PrintWriter(System.out, true); TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter); new ClassReader(bytes).accept(traceClassVisitor, parsingOptions); } }
PrintOpcodeTable.java
package run; import lsieun.utils.OpcodeConst; /** * Print opcode between {@link #start} and {@link #stop}. */ public class PrintOpcodeTable { private static int start = 0; private static int stop = 256; public static void main(String[] args) throws Exception { printOpcode(); } public static void printOpcode() { if (start < 0) { start = 0; } if (stop > 256) { stop = 256; } int num = stop - start; int column = 4; int row = num / column; int remainder = num % column; if (remainder != 0) { row++; } System.out.println("| opcode | mnemonic symbol | opcode | mnemonic symbol | opcode | mnemonic symbol | opcode | mnemonic symbol |"); System.out.println("|--------|-----------------|--------|-----------------|--------|-----------------|--------|-----------------|"); for (int i = 0; i < row; i++) { int val1 = start + i; int val2 = val1 + row; int val3 = val2 + row; int val4 = val3 + row; String line = String.format("| %-6d | %-15s | %-6d | %-15s | %-6d | %-15s | %-6d | %-15s |", val1, getOpcodeName(val1), val2, getOpcodeName(val2), val3, getOpcodeName(val3), val4, getOpcodeName(val4) ); System.out.println(line); } } public static String getOpcodeName(int i) { if (i < 0 || i >= OpcodeConst.OPCODE_NAMES_LENGTH) { return ""; } if (i < start || i >= stop) { return ""; } String opcodeName = OpcodeConst.getOpcodeName(i); if (OpcodeConst.ILLEGAL_OPCODE.equals(opcodeName)) { opcodeName = ""; } return opcodeName; } }