博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASM3.0学习(三)
阅读量:5947 次
发布时间:2019-06-19

本文共 3911 字,大约阅读时间需要 13 分钟。

hot3.png

2.3工具

除了ClassVisitor接口,以及与之相关的三个组件ClassReader ClassAdapter和ClassWriter,ASM在org.objectweb.asm.util包中提供了一些工具用来帮助开发类生成器或者适配器,这些工具在运行时并不需要。ASM提供了一些实用类用来在运行时操作内部名称,类型描述符以及方法描述符。所有的这些工具将在下面介绍。
2.3.1类型
就像在前面章节中见到的,ASM API将编译后的class中的java类型以内部名称或者类型描述符的方式展现出来。当然,也可以将这些类型还原成源代码中定义的样子,这样就更便于阅读。但是,这需要在ClassReader和ClassWriter之间进行系统转换,但是这会降低性能。这就是为什么ASM没有透明地转换内部名称和类型描述符为源代码中对等的形式。尽管如此,ASM还是提供了Type类用来在需要的时候手工地进行转换。
一个Type对象代表了一个java类型,它可以通过类型描述符或者Class对象来构造。这个Type类也包含了一些静态变量,用来表示基本类型,例如Type.INT_TYPE是int类型的Type对象。
getInternalName方法返回一个Type的内部名称,例如,Type.getType(String.class).getInternalName()返回了String类的内部名称”java/lang/String”.这个方法只能用于类或者借口类型。
getDescriptor方法返回一个Type的描述符,例如,你可以使用Type.getType(String.class).getDescriptor()来代替”Ljava/lang/String;”。或者,使用Type.INT_TYPE.getDescriptor()来代替I。
Type类也提供了一些静态方法用来获取一个方法的参数的Type对象和返回值的Type对象,主要是通过它的类型描述符或者java.lang.reflect.Method对象来获得。例如,Type.getArgumentTypes(“(I)V”)返回一个包含Type.INT_TYPE的数组,同样地Type.getReturnType(“(I)V”)返回一个Type.VOID_TYPE对象。
2.3.2 TraceClassVisitor
为了检查类的生成或者转换是否如你期望,单靠ClassWriter返回的字节数组是没有多大帮助的,因为它不可读。相比较而言,一个文本表示更易于阅读和使用,而这就是TraceClassVisitor提供的。这个类,就如它的名字暗示的一样,实现了ClassVisitor借口,并且构造解析过的类的文本表示。因此,你可以使用TraceClassVisitor来替代ClassWriter,这样你可以跟踪真正生成的是什么。更好的办法是同时使用这两者,TraceClassVisitor可以跟踪代码生成,除此之外,它也可以将所有的调用委托给另外一个visitor,如ClassWriter:
ClassWriter cw = new ClassWriter(0);
TraceClassVisitor cv = new TraceClassVisitor(cw, printWriter);
cv.visit(...);
...
cv.visitEnd();
byte b[] = cw.toByteArray();
上面的代码创建了一个TraceClassVisitor,然后委托所有对它的调用给cw,并且将对这些方法的调用以文本方式交给printWriter来打印。例如,在2.2.3章节中的例子使用TraceClassVisitor会输出如下内容:
// class version 49.0 (49)
// access flags 1537
public abstract interface pkg/Comparable implements pkg/Mesurable {
// access flags 25
public final static I LESS = -1
// access flags 25
public final static I EQUAL = 0
// access flags 25
public final static I GREATER = 1
// access flags 1025
public abstract compareTo(Ljava/lang/Object;)I
}
注意,为了弄清楚在转换链中到底发生了什么,你可以在生成类或者转换链过程的任何点使用TraceClassVisitor,而不仅仅是在ClassWriter之前使用。注意,通过这个类生成的类的文本表示可以通过String.equals()很容易地进行比较。
2.3.3 CheckClassAdapter
ClassWriter并不会检查它的方法调用是否按照合适的顺序以及参数是否有效。这样就可能生成无效的代码,而被java虚拟机的验证工具所拒绝。为了尽可能地检测出这些错误,可以使用CheckClassAdapter。和TraceClassVisitor一样,这个类也实现了ClassVisitor接口,它也会将对它的方法调用委托给其他的ClassVisitor,例如一个TraceClassVisitor或者ClassWriter。尽管如此,除了打印类的文本表示,这个类会在将方法调用委托给下一个ClassVisitor之前,检查对它的方法调用顺序是否合理,以及参数是否有效。如果发生错误,将会抛出IllegalStateException或者IllegalArgumentException。
为了检查一个类,并且打印它的文本表示,最终创建一个字节数组,你可以参考下面的代码:
ClassWriter cw = new ClassWriter(0);
TraceClassVisitor tcv = new TraceClassVisitor(cw, printWriter);
CheckClassAdapter cv = new CheckClassAdapter(tcv);
cv.visit(...);
...
cv.visitEnd();
byte b[] = cw.toByteArray();
注意,如果这些ClassVisitor的顺序不同,那么它们会以不同的顺序执行。例如,下面的代码会导致在跟踪代码以后再检查类。
ClassWriter cw = new ClassWriter(0);
CheckClassAdapter cca = new CheckClassAdapter(cw);
TraceClassVisitor cv = new TraceClassVisitor(cca, printWriter);
就像TraceClassVisitor一样,为了检查类是否有效,你也可以在生成类或者转换类的链的任
何节点使用CheckClassAdapter,而不仅仅是在ClassWriter之前。
2.3.4 ASMifierClassVisitor
这个类也实现了ClassVisitor接口,它的每个方法会打印出调用它的java代码。例如,调用visitEnd会打印出cv.visitEnd();,结果是,当这个visitor解析一个类时,它会打印出使用ASM来生成这个类的源代码。当你使用这个类去解析一个存在的类时,你会发现它很有用。例如,如果你不知道如何使用ASM来生成一些编译后的类,那么你可以先写出这些类的源代码,然后使用javac来编译,再然后使用ASMifierClassVisitor来解析,这样就能够得到使用ASM来生成这些类的源代码了。
ASMifierClassVisitor可以通过命令行直接使用,如下面的例子:
java -classpath asm.jar:asm-util.jar \
org.objectweb.asm.util.ASMifierClassVisitor \
java.lang.Runnable
生成的代码经过缩进以后,就是下面的代码:
package asm.java.lang;
import org.objectweb.asm.*;
public class RunnableDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
"java/lang/Runnable", null, "java/lang/Object", null);
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "run", "()V",
null, null);
mv.visitEnd();

 

 

转载于:https://my.oschina.net/u/2292306/blog/3005990

你可能感兴趣的文章
【原创】FIFO的基础和时序分析学习
查看>>
Nginx学习之十一-Nginx启动框架处理流程
查看>>
[置顶] 吃论扯谈---吃货和Office 365订阅的关系
查看>>
蓝桥杯 基础练习 十六进制转十进制(水题,进制转换)
查看>>
php有些系统会报错或提示 Cannot modify header information - headers already sent by
查看>>
从零開始开发Android版2048 (五) 撤销的实现
查看>>
OpenGL 4 : 一个漂亮的心 For you, My Love
查看>>
2007年硕士研究生面试时的英文自我介绍
查看>>
POJ1789:Truck History(Prim算法)
查看>>
SD卡
查看>>
使用servletAPI三种方式简单示例
查看>>
单片机不同晶振怎么计算延迟时间?
查看>>
视频会议十大开源项目排行
查看>>
SQL Server Management Studio 简单使用说明
查看>>
【前端】javascript判断undefined、null、NaN;字符串包含等
查看>>
玩转iOS开发 - 数据缓存
查看>>
李洪强-C语言3-数组
查看>>
C# 6.0的字典(Dictionary)的语法
查看>>
使用ShareSDK实现第三方授权登录、分享以及获取用户资料效果,项目中包含:源码+效果图+项目结构图...
查看>>
三级联动效果
查看>>