ASM框架使用(四)--泛型與註解
阿新 • • 發佈:2018-11-13
泛型
對於泛型型別Type的解析,必須按照下面的順序
訪問方法簽名按照下面的順序
訪問類簽名的順序
其中大部分方法都會返回一個SignatureVisitor,用於訪問一個type簽名。
SignatureVisitor返回SignatureVisitors(不能返回null)。
ASM提供SignatureReader和SugnatureWriter用於解析和建立簽名。
SignatureReader解析簽名並呼叫SignatureVisitor中相應的方法,SugnatureWriter根據收到的方法呼叫建立簽名。
public class Node<T> { int key; T value; public <K>void do1(K a){ System.out.println( "ss1"+a); } public static void main(String[] args) { Node m=new Node(); m.do1(4); } }
給Node類新增一個泛型M,也給方法新增一個泛型宣告M:
public class GenericAdapter extends ClassVisitor implements Opcodes { public GenericAdapter( ClassVisitor classVisitor) { super(ASM6, classVisitor); } @Override public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings) { if (s2!=null) { s2=addGernicM(s2); } return super.visitMethod(i, s, s1, s2, strings); } @Override public void visit(int i, int i1, String s, String s1, String s2, String[] strings) { if (s1!=null) s1=addGernicM(s1); super.visit(i, i1, s, s1, s2, strings); } private String addGernicM(String s1) { SignatureWriter sw = new SignatureWriter(); SignatureVisitor sa = new AddGernicMVisiter(sw); SignatureReader sr = new SignatureReader(s1); sr.acceptType(sa); return sw.toString(); } public static void main(String[] args) throws IOException { ClassReader classReader=new ClassReader("bytecode.Node"); ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_MAXS); TraceClassVisitor traceClassVisitor=new TraceClassVisitor(cw,new PrintWriter(System.out)); GenericAdapter genericAdapter=new GenericAdapter(traceClassVisitor); classReader.accept(genericAdapter,ClassReader.EXPAND_FRAMES); } class AddGernicMVisiter extends SignatureVisitor{ private SignatureVisitor signatureVisitor; public AddGernicMVisiter(SignatureVisitor signatureVisitor) { super(ASM6); this.signatureVisitor=signatureVisitor; } @Override public void visitClassType(String s) { signatureVisitor.visitClassType(s+"M:Ljava/lang/Object;"); } } }
註解
只要一個註解的作用域不是RetentionPolicy.SOURCE,那麼它就會儲存在編譯後的class檔案中。如果作用域是RetentionPolicy.RUNTIME,那麼可以在執行時被反射獲取。
ASM框架通過AnnotationVisitor來訪問和修改註解。
訪問順序:
visitAnnotation方法返回Null可以移除一個註解,
下面分別移除了 欄位上的註解,類上的註解,以及獲取註解的值。
public class AnnotationAdapter extends ClassVisitor implements Opcodes{ public AnnotationAdapter(ClassVisitor classVisitor) { super(ASM6, classVisitor); } @Override public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { FieldVisitor fv= super.visitField(access, name, descriptor, signature, value); if (fv!=null) fv=new RemoveFieldAnnotation(fv);//移除一個註解 return fv; } /** * 移除類上的ClassR1註解 * @param descriptor * @param visible * @return */ @Override public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { if (descriptor.equals("Lcom/liu/asm/ClassR1;")){ return null; } return new AnnotationValueVisitor(super.visitAnnotation(descriptor, visible)); } public static void main(String[] args) throws IOException { ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_MAXS); TraceClassVisitor tv=new TraceClassVisitor(cw,new PrintWriter(System.out)); AnnotationAdapter addFiled=new AnnotationAdapter(tv); ClassReader classReader=new ClassReader("com.liu.asm.Student"); classReader.accept(addFiled,ClassReader.EXPAND_FRAMES); } class RemoveFieldAnnotation extends FieldVisitor{ public RemoveFieldAnnotation(FieldVisitor fieldVisitor) { super(ASM6,fieldVisitor); } @Override public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { if (descriptor.equals("Lcom/liu/asm/ClassR1;")){ return null; } return new AnnotationValueVisitor(super.visitAnnotation(descriptor, visible)); } } class AnnotationValueVisitor extends AnnotationVisitor{ public AnnotationValueVisitor( AnnotationVisitor annotationVisitor) { super(ASM6, annotationVisitor); } @Override public void visit(String name, Object value) { System.out.println("註解"+name+value); super.visit(name, value); } } }
向後相容性
學習新的class檔案特性對位元組碼產生器,分析器和介面卡的影響是重要的,因為二進位制實現的相容性問題。
對於位元組碼生成器,新特性對它沒什麼影響。
而分析器和介面卡則可能會收到影響。
因此,制定了以下規則保證向後相容性:
- ASM version X是為Java版本小於等於x的類寫的,不能用於高於版本x的
- code written for ASM X不能用高於x版本的特性