ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java ASM系列:(035)TraceClassVisitor介绍

2021-07-04 07:01:50  阅读:205  来源: 互联网

标签:printWriter Java String TraceClassVisitor new import final ASM


本文属于[Java ASM系列一:Core API](https://blog.51cto.com/lsieun/2924583)当中的一篇。 `TraceClassVisitor` class extends the `ClassVisitor` class, and builds **a textual representation of the visited class**. ## 1. TraceClassVisitor类 ### 1.1 class info 第一个部分,`TraceClassVisitor`类继承自`ClassVisitor`类,而且有`final`修饰,因此不会存在子类。 ```java public final class TraceClassVisitor extends ClassVisitor { } ``` ### 1.2 fields 第二个部分,`TraceClassVisitor`类定义的字段有哪些。`TraceClassVisitor`类有两个重要的字段,一个是`PrintWriter printWriter`用于打印;另一个是`Printer p`将class转换成文字信息。 ```java public final class TraceClassVisitor extends ClassVisitor { private final PrintWriter printWriter; // 真正打印输出的类 public final Printer p; // 信息采集器 } ``` ### 1.3 constructors 第三个部分,`TraceClassVisitor`类定义的构造方法有哪些。 ```java public final class TraceClassVisitor extends ClassVisitor { public TraceClassVisitor(final PrintWriter printWriter) { this(null, printWriter); } public TraceClassVisitor(final ClassVisitor classVisitor, final PrintWriter printWriter) { this(classVisitor, new Textifier(), printWriter); } public TraceClassVisitor(final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter) { super(Opcodes.ASM10_EXPERIMENTAL, classVisitor); this.printWriter = printWriter; this.p = printer; } } ``` ### 1.4 methods 第四个部分,`TraceClassVisitor`类定义的方法有哪些。对于`TraceClassVisitor`类的`visit()`、`visitField()`、`visitMethod()`和`visitEnd()`方法,会分别调用`Printer.visit()`、`Printer.visitField()`、`Printer.visitMethod()`和`Printer.visitClassEnd()`方法。 ```java public final class TraceClassVisitor extends ClassVisitor { @Override public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { p.visit(version, access, name, signature, superName, interfaces); super.visit(version, access, name, signature, superName, interfaces); } @Override public FieldVisitor visitField(final int access, final String name, final String descriptor, final String signature, final Object value) { Printer fieldPrinter = p.visitField(access, name, descriptor, signature, value); return new TraceFieldVisitor(super.visitField(access, name, descriptor, signature, value), fieldPrinter); } @Override public MethodVisitor visitMethod(final int access, final String name, final String descriptor, final String signature, final String[] exceptions) { Printer methodPrinter = p.visitMethod(access, name, descriptor, signature, exceptions); return new TraceMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions), methodPrinter); } @Override public void visitEnd() { p.visitClassEnd(); if (printWriter != null) { p.print(printWriter); // Printer和PrintWriter进行结合 printWriter.flush(); } super.visitEnd(); } } ``` ## 2. 如何使用TraceClassVisitor类 使用`TraceClassVisitor`类,很重点的一点就是选择`Printer`类的具体实现,可以选择`ASMifier`类,也可以选择`Textifier`类(默认): ```text boolean flag = true or false; Printer printer = flag ? new ASMifier() : new Textifier(); PrintWriter printWriter = new PrintWriter(System.out, true); TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter); ``` ### 2.1 生成新的类 ```java import lsieun.utils.FileUtils; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.util.TraceClassVisitor; import java.io.PrintWriter; import static org.objectweb.asm.Opcodes.*; public class TraceClassVisitorExample01Generate { public static void main(String[] args) throws Exception { String relative_path = "sample/HelloWorld.class"; String filepath = FileUtils.getFilePath(relative_path); // (1) 生成byte[]内容 byte[] bytes = dump(); // (2) 保存byte[]到文件 FileUtils.writeBytes(filepath, bytes); } public static byte[] dump() throws Exception { // (1) 创建ClassWriter对象 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); PrintWriter printWriter = new PrintWriter(System.out); TraceClassVisitor cv = new TraceClassVisitor(cw, printWriter); // (2) 调用visitXxx()方法 cv.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld", null, "java/lang/Object", null); { FieldVisitor fv1 = cv.visitField(ACC_PRIVATE, "intValue", "I", null, null); fv1.visitEnd(); } { FieldVisitor fv2 = cv.visitField(ACC_PRIVATE, "strValue", "Ljava/lang/String;", null, null); fv2.visitEnd(); } { MethodVisitor mv1 = cv.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv1.visitCode(); mv1.visitVarInsn(ALOAD, 0); mv1.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); mv1.visitInsn(RETURN); mv1.visitMaxs(0, 0); mv1.visitEnd(); } { MethodVisitor mv2 = cv.visitMethod(ACC_PUBLIC, "test", "()V", null, null); mv2.visitCode(); mv2.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv2.visitLdcInsn("Hello World"); mv2.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); mv2.visitInsn(RETURN); mv2.visitMaxs(2, 1); mv2.visitEnd(); } cv.visitEnd(); // (3) 调用toByteArray()方法 return cw.toByteArray(); } } ``` ### 2.2 修改已有的类 ```java import lsieun.utils.FileUtils; import org.objectweb.asm.Cla***eader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.util.TraceClassVisitor; import java.io.PrintWriter; public class TraceClassVisitorExample02Transform { public static void main(String[] args) { String relative_path = "sample/HelloWorld.class"; String filepath = FileUtils.getFilePath(relative_path); byte[] bytes1 = FileUtils.readBytes(filepath); //(1)构建Cla***eader Cla***eader cr = new Cla***eader(bytes1); //(2)构建ClassWriter ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); //(3)串连ClassVisitor int api = Opcodes.ASM9; PrintWriter printWriter = new PrintWriter(System.out); TraceClassVisitor tcv = new TraceClassVisitor(cw, printWriter); ClassVisitor cv = new MethodTimerVisitor(api, tcv); //(4)结合Cla***eader和ClassVisitor int parsingOptions = Cla***eader.SKIP_DEBUG | Cla***eader.SKIP_FRAMES; cr.accept(cv, parsingOptions); //(5)生成byte[] byte[] bytes2 = cw.toByteArray(); FileUtils.writeBytes(filepath, bytes2); } } ``` ### 2.3 打印ASM代码 ```java import org.objectweb.asm.Cla***eader; import org.objectweb.asm.util.ASMifier; 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; /** * 这里的代码是参考自{@link org.objectweb.asm.util.Printer#main} */ public class ASMPrint { public static void main(String[] args) throws IOException { // (1) 设置参数 String className = "sample.HelloWorld"; int parsingOptions = Cla***eader.SKIP_FRAMES | Cla***eader.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 Cla***eader(className).accept(traceClassVisitor, parsingOptions); } } ``` ## 3. 总结 本文对`TraceClassVisitor`类进行了介绍,内容总结如下: - 第一点,从整体上来说,`TraceClassVisitor`类的作用是什么。它能够将class文件的内容转换成文字输出。 - 第二点,从结构上来说,`TraceClassVisitor`类的各个部分包含哪些信息。 - 第三点,从使用上来说,`TraceClassVisitor`类的输出结果依赖于`Printer`类的具体实现,可以选择`ASMifier`类输出ASM代码,也可以选择`Textifier`类输出Instruction信息。

标签:printWriter,Java,String,TraceClassVisitor,new,import,final,ASM
来源: https://blog.51cto.com/lsieun/2973664

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有