Generics
为了向后兼容,关于泛型的信息并不是直接存在type或者method descriptors中的,而是存在type, method和class signatures中。而这些signatures是存在class/field/method declarations中的。编译器会使用这些信息做静态类型检查,不过编译的时候不会使用这些信息,具体运行的时候也是使用type casts或者reflection来实现的。
Type signature
基本规则如下:
示例:
Method Signature
示例:
Class Signature
SignatureVisitor
执行顺序
基本方法还是SignatureReader->SignatureVisitor->SignatureWriter
例子
Annotation
如果Annotation的retention policy不是RetentionPolicy.Source,那么annotations都会存在compiled class中,可以通过reflection API获取。
Annotations在源代码中可能有多种形式,比如@Deprecated,或者@Retention(RetentionPolicy.CLASS)等。不过,几乎所有的annotations是以一个annotation type开头,后面跟着一串name value对,而value只能是: 1. primitive, Class, String
2. enum
3. annotation values//annotation能够嵌套其他的annotation
4. arrays of the above values
AnnotationVisitor
执行顺序
例子-删除annotation
很简单,在ClassVisitor执行visitAnnotation返回null即可。
例子-添加annotation
所有的在visitAnnotation之后的方法都需要重载来确认确实添加了Annotation。
Debug
使用javac -g编译出来的classes会包含调试信息,主要就是包含sourcefile的名称,line numbers等。
ASM提供了visitSource, visitLineNumber, visitLocalVariable(获取具体variable names)
Tree API
ClassNode是ClassVisitor的一种,不过通过ClassNode有机会非线性访问数据。
基本使用模式
ClassReader classReader = new ClassReader(source);
ClassNode classNode = new ClassNode();
classReader.accept(classNode, 0);
ClassWriter classWriter = new ClassWriter(0);
classNode.accept(classWriter);
ClassReader classReader = new ClassReader(source);
ClassWriter classWriter = new ClassWriter(0);
ClassVisitor classVisitor = new ClassVisitor(ASM7, classWriter) {
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
final MethodVisitor methodVisitor =
super.visitMethod(access, name, desc, signature, exceptions);
MethodNode methodNode = new MethodNode(access, name, desc, signature, exceptions) {
public void visitEnd() {
// transform or analyze method code using tree API
accept(methodVisitor);
}
};
}
};
classReader.accept(classVisitor, 0);
操作指令
第一种,线性添加
MethodNode methodNode = new MethodNode(...);
methodNode.instructions.add(new VarInsnNode(ALOAD, 0));
或者
MethodNode methodNode = new MethodNode(...);
methodNode.visitVarInsn(ALOAD, 0);
第二种,使用记录下来的AbstractInsnNode来添加
MethodNode methodNode = new MethodNode(...);
methodNode.visitVarInsn(ALOAD, 0);
AbstractInsnNode ptr = methodNode.instructions.getLast();
methodNode.visitVarInsn(ALOAD, 1);
// inserts an instruction between ALOAD 0 and ALOAD 1
methodNode.instructions.insert(ptr, new VarInsnNode(ALOAD, 0));
...