java asm tree

什么是ASM树API: ASM树API是ASM的一部分,可让您创建/修改内存中的类。 该类被视为信息树。 像整个类一样,它是ClassNode的实例,其中包含FieldNode对象的列表,MethodNode对象的列表等。本文假设读者已经在这里阅读了第一部分。

通过树API的简单类:让我们使用树API创建我们的第一类。 我再次要直接进入代码示例,因为没有什么比代码示例更好。 生成的类具有打印“ Hello World!”的主要方法。

TreeAPIDemo.java

package com.geekyarticles.asm;import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;public class TreeAPIDemo {public static void main(String [] args) throws Exception{ClassNode classNode=new ClassNode(4);//4 is just the API version number//These properties of the classNode must be setclassNode.version=Opcodes.V1_6;//The generated class will only run on JRE 1.6 or aboveclassNode.access=Opcodes.ACC_PUBLIC;classNode.signature="Lcom/geekyarticles/asm/Generated;";classNode.name="com/geekyarticles/asm/Generated";classNode.superName="java/lang/Object";//Create a methodMethodNode mainMethod=new MethodNode(4,Opcodes.ACC_PUBLIC|Opcodes.ACC_STATIC,"main", "([Ljava/lang/String;)V",null, null);mainMethod.instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));mainMethod.instructions.add(new LdcInsnNode("Hello World!"));mainMethod.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"));mainMethod.instructions.add(new InsnNode(Opcodes.RETURN));//Add the method to the classNodeclassNode.methods.add(mainMethod);//Write the classClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES);classNode.accept(cw);//Dump the class in a fileFile outDir=new File("out/com/geekyarticles/asm");outDir.mkdirs();DataOutputStream dout=new DataOutputStream(new FileOutputStream(new File(outDir,"Generated.class")));dout.write(cw.toByteArray());dout.flush();dout.close();}
}

如您所见,代码非常简单。 与BCEL相比,主要优点是与BCEL不同,ASM不需要您将每个常量显式添加到常量池中。 相反,ASM会照顾常量池本身。

读取类文件: ClassNode是ClassVisitor。 因此,读取用于树API的类就像创建ClassReader对象并使用它读取类文件一样简单,同时将ClassNode对象作为其accept方法传递给参数。 完成此操作后,将通过类中存在的所有信息完全初始化传递的ClassNode。 在下面的示例中,我们将打印类中的所有方法。

TreeAPIClassReaderDemo.java

package com.geekyarticles.asm;import java.io.FileInputStream;
import java.io.InputStream;import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;public class TreeAPIClassReaderDemo {public static void main(String[] args) throws Exception{InputStream in=new FileInputStream("out/com/geekyarticles/asm/Generated.class");ClassReader cr=new ClassReader(in);ClassNode classNode=new ClassNode();//ClassNode is a ClassVisitorcr.accept(classNode, 0);//Let's move through all the methodsfor(MethodNode methodNodeclassNode.methods){System.out.println(methodNode.name+"  "+methodNode.desc);}}}

修改类文件:修改类文件是上述两个过程的组合。 我们首先以通常的方式读取类,对数据进行必要的更改,然后将其写回到文件中。 以下程序实现了一些日志代码的自动注入。 当前,我们的Logger类仅打印到标准输出。 @Loggable注释的每个方法在开始和返回时都将被记录。 在此,我们不记录throw-exception。 但是,也可以通过检查操作码ATHROW以相同的方式实现。

LoggingInsertion.java

package com.geekyarticles.asm;import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Iterator;import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;public class LoggingInsertion {public static void main(String[] args) throws Exception{InputStream in=LoggingInsertion.class.getResourceAsStream("/com/geekyarticles/asm/LoggingTest.class");ClassReader cr=new ClassReader(in);ClassNode classNode=new ClassNode();cr.accept(classNode, 0);//Let's move through all the methodsfor(MethodNode methodNodeclassNode.methods){System.out.println(methodNode.name+"  "+methodNode.desc);boolean hasAnnotation=false;if(methodNode.visibleAnnotations!=null){for(AnnotationNode annotationNodemethodNode.visibleAnnotations){if(annotationNode.desc.equals("Lcom/geekyarticles/asm/Loggable;")){hasAnnotation=true;break;}}}if(hasAnnotation){//Lets insert the begin loggerInsnList beginList=new InsnList();beginList.add(new LdcInsnNode(methodNode.name));beginList.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/geekyarticles/asm/Logger", "logMethodStart", "(Ljava/lang/String;)V"));Iterator<AbstractInsnNode> insnNodes=methodNode.instructions.iterator();while(insnNodes.hasNext()){System.out.println(insnNodes.next().getOpcode());}methodNode.instructions.insert(beginList);System.out.println(methodNode.instructions);//A method can have multiple places for return//All of them must be handled.insnNodes=methodNode.instructions.iterator();while(insnNodes.hasNext()){AbstractInsnNode insn=insnNodes.next();System.out.println(insn.getOpcode());if(insn.getOpcode()==Opcodes.IRETURN||insn.getOpcode()==Opcodes.RETURN||insn.getOpcode()==Opcodes.ARETURN||insn.getOpcode()==Opcodes.LRETURN||insn.getOpcode()==Opcodes.DRETURN){InsnList endList=new InsnList();endList.add(new LdcInsnNode(methodNode.name));endList.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/geekyarticles/asm/Logger", "logMethodReturn", "(Ljava/lang/String;)V"));methodNode.instructions.insertBefore(insn, endList);}}}}//We are done now. so dump the classClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES);classNode.accept(cw);File outDir=new File("out/com/geekyarticles/asm");outDir.mkdirs();DataOutputStream dout=new DataOutputStream(new FileOutputStream(new File(outDir,"LoggingTest.class")));dout.write(cw.toByteArray());dout.flush();dout.close();}}

LoggingTest.java

package com.geekyarticles.asm;public class LoggingTest {public static void run1(){System.out.println("run 1");}@Loggablepublic static void run2(){System.out.println("run 2");}@Loggablepublic static void main(String [] args){run1();run2();}
}

记录器

package com.geekyarticles.asm;public class Logger {public static void logMethodStart(String methodName){System.out.println("Starting method: "+methodName);}public static void logMethodReturn(String methodName){System.out.println("Ending method: "+methodName);}
}

Loggable.java

package com.geekyarticles.asm;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {}

如果运行此程序,则生成的文件将与Logger类相关。 手动将Logger类复制到out目录中的正确软件包。 如果运行生成的类(它是LoggingTest类的修改版本),则将输出以下内容。

bash-4.1$ java  com.geekyarticles.asm.LoggingTest
Starting method: main
run 1
Starting method: run2
run 2
Ending method: run2
Ending method: main

请注意,与普通列表不同,可以在迭代InsnList对象时对其进行修改。 任何更改都会立即反映出来。 因此,如果在当前位置之后插入了一些指令,则也将对其进行迭代。

参考: 使用ASM 4处理Java类文件–第二部分: JCG合作伙伴提供的 Tree API   极客文章博客上的Debasish Ray Chawdhuri。

翻译自: https://www.javacodegeeks.com/2012/02/manipulating-java-class-files-with-asm_22.html

java asm tree

java asm tree_使用ASM 4处理Java类文件–第二部分:Tree API相关推荐

  1. 使用ASM 4处理Java类文件–第二部分:Tree API

    什么是ASM树API: ASM树API是ASM的一部分,可让您创建/修改内存中的类. 该类被视为信息树. 像整个类一样,它是ClassNode的实例,其中包含FieldNode对象列表,MethodN ...

  2. Java基础篇(02):特殊的String类,和相关扩展API

    本文源码:GitHub·点这里 || GitEE·点这里 一.String类简介 1.基础简介 字符串是一个特殊的数据类型,属于引用类型.String类在Java中使用关键字final修饰,所以这个类 ...

  3. java string 包含http_Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件)...

    一.HttpPost上传文件 public static String getSuffix(final MultipartFile file){ if(file == null || file.get ...

  4. java.lang.IllegalArgumentException: Name for argument type [java.lang.Integer] not available异常

    这个异常的大致意思是:参数类型的名称[java.lang.Integer]不可用,并且在类文件中也找不到参数名称信息. 就是说前端发起的请求的参数和后台接收的参数对应不上,我们项目采用前后端分离前端采 ...

  5. CGLIB依赖ASM(关于java字节码框架ASM的学习)

    本文转自: http://www.cnblogs.com/liuling/archive/2013/05/25/asm.html 一.什么是ASM ASM是一个java字节码操纵框架,它能被用来动态生 ...

  6. 使用ASM 4处理Java类文件–第一部分:世界,您好!

    什么是ASM :ASM是一个用于处理Java字节码的开源Java库. 因此,它具有与Apache BCEL相同的目的. 由于本文假定读者具有Java类文件格式的某些知识,因此建议在此处进行阅读. 那么 ...

  7. Java字节码框架ASM简介

    Java字节码框架ASM简介 1. ASM概述 1.1 ASM简介 1.2 ASM提供API 1.3 ASM核心模块 2. ASM应用 2.1 ASM依赖 2.2 代码实现 2.3 测试验证 1. A ...

  8. Java转换成汇编asm程序

    Java转换成汇编asm程序 背景: 我之前写了一篇文章,其实也是受人之托,实现成绩排序 原文链接: https://blog.csdn.net/frdevolcqzyxynjds/article/d ...

  9. 深入理解Java虚拟机知乎_深入理解Java虚拟机(类文件结构)

    深入理解Java虚拟机(类文件结构) 欢迎关注微信公众号:BaronTalk,获取更多精彩好文! 之前在阅读 ASM 文档时,对于已编译类的结构.方法描述符.访问标志.ACC_PUBLIC.ACC_P ...

最新文章

  1. 程序员面试时,不小心说了真话…...
  2. android好用的第三方库2018使用总结
  3. Spring5源码 - 13 Spring事件监听机制_@EventListener源码解析
  4. 单片机流星灯_51单片机拖尾灯实现
  5. windows时间显示到秒
  6. Nginx实战部署常用功能演示(超详细版),绝对给力~~~
  7. raid0 raid1 raid5 raid10工作模式的工作原理及特点
  8. 感谢党,软考过了。系统集成项目管理project师
  9. CUDA内存分配、释放、传输,固定内存
  10. 火车图 、jackson图
  11. 小虾教你网购组装电脑单
  12. 计算机组成原理中EMAR是什么,计算机组成原理复习资料+试题
  13. ubuntu14.04中安装opencv2.4.11
  14. html简单网页设计实验实践结论,网页设计社会实践报告
  15. 视频教程-通俗易懂的RPC框架Dubbo视频教程-Java
  16. 我眼中的架构师:一个优秀的架构师应该具备什么?
  17. 腾讯云IM Web端支持发送语音消息
  18. html5制作学生积分系统,科学网—CLASS极简教程 - 钱磊的博文
  19. 翼支付门户架构之搭建SpringMvc环境
  20. 《web开发: Ajax 介绍》

热门文章

  1. 检测性异常VS非检测性异常
  2. Linux基本目录解释
  3. 云服务器的购买和宝塔面板的使用
  4. shell文本处理工具grep
  5. 魔术方法 类 序列化_Java序列化魔术方法及其示例使用
  6. api 获取网络使用情况_您的API是什么情况?
  7. 高频变压器_变压器图案
  8. java ee打印功能_Java EE 8的前5个新功能
  9. wso2 安装_WSO2注册表安装简介
  10. tdd java_Java TDD简介–第2部分