2.2 接口和组件
2.2.1 介绍
ASM API 生成和转换Java字节码的操作都是基于ClassVisitor这个接口的。这个接口中的方法的方法名都是与字节码文件中节的名字对应的。
ClassVisitor接口的代码清单:
public interface ClassVisitor {
void visit(int version, int access, String name, String signature, String superName, String[] interfaces);
void visitSource(String source, String debug);
void visitOuterClass(String owner, String name, String desc);
AnnotationVisitor visitAnnotation(String desc, boolean visible);
void visitAttribute(Attribute attr);
void visitInnerClass(String name, String outerName, String innerName, int access);
FieldVisitor visitField(int access, String name, String desc, String signature, Object value);
MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions);
void visitEnd();
}
ClassVisitor接口中的方法的调用是有顺序的,这个顺序如下所示:
>调用visit方法
>最多调用一次visitSource
>最多调用一次visitOuterClass
>调用visitAnnotation、visitAttribute任意次
>调用visitInnerClass、visitField、visitMethod任意次
>调用visitEnd
ASM提供了3个基于ClassVisitor几口的核心组件,用于生成和转换类:
>ClassReader类,该类解析byte数组中的Java类字节码,并且负责调用ClassVisitor接口实例(作为参数传递给ClassReader的accept方法)中相应的的visitXXX方法。该类可以看做是一个事件生产者。
>ClassWriter类,该类实现了ClassVisitor接口,用于直接以二进制的形式构建已编译的类。可以从该类实例中获得一个包含字节码的byte数组。该类可以看做是一个事件消费者。
>ClassAdaptor类,该类实现了ClassVisitor接口,它通过委派的方式调用其他的ClassVisitor接口实例的方法来提供ClassVisitor接口所要求实现的方法。该类可以看做是一个事件过滤器。
下一节将给出具体的例子,来说明如何生成和转换类。
2.2.2 解析类
解析一个类,只需要ClassReader这一个组件。
举一个例子,打印指定类的字节码信息:
import java.io.IOException;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
public class ClassPrinter implements ClassVisitor {
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
System.out.println(name + " extends " + superName + " {");
}
public void visitSource(String source, String debug) {
}
public void visitOuterClass(String owner, String name, String desc) {
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return null;
}
public void visitAttribute(Attribute attr) {
}
public void visitInnerClass(String name, String outerName, String innerName, int access) {
}
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
System.out.println(" " + desc + " " + name);
return null;
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
System.out.println(" " + name + desc);
return null;
}
public void visitEnd() {
System.out.println("}");
}
public static void main(String[] args) throws IOException {
ClassPrinter classPrinter = new ClassPrinter();
ClassReader classReader = new ClassReader("java.lang.Object");
classReader.accept(classPrinter, 0);
}
}
运行上面的程序,如果没有错误出现的话,应该会输出如下内容:
java/lang/Object extends null {
<init>()V
registerNatives()V
getClass()Ljava/lang/Class;
hashCode()I
equals(Ljava/lang/Object;)Z
clone()Ljava/lang/Object;
toString()Ljava/lang/String;
notify()V
notifyAll()V
wait(J)V
wait(JI)V
wait()V
finalize()V
<clinit>()V
}