View Javadoc

1   /***************************************************************************************
2    * Copyright (c) Jonas Bon?r, Alexandre Vasseur. All rights reserved.                 *
3    * http://aspectwerkz.codehaus.org                                                    *
4    * ---------------------------------------------------------------------------------- *
5    * The software in this package is published under the terms of the LGPL license      *
6    * a copy of which has been included with this distribution in the license.txt file.  *
7    **************************************************************************************/
8   package org.codehaus.aspectwerkz.annotation.instrumentation.asm;
9   
10  import org.objectweb.asm.ClassVisitor;
11  import org.objectweb.asm.Attribute;
12  import org.objectweb.asm.CodeVisitor;
13  import org.objectweb.asm.Label;
14  import org.objectweb.asm.attrs.RuntimeInvisibleAnnotations;
15  import org.objectweb.asm.attrs.Annotation;
16  import org.objectweb.asm.attrs.RuntimeVisibleAnnotations;
17  import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
18  import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
19  
20  import java.util.List;
21  import java.util.Iterator;
22  
23  /***
24   * Helper visitor to extract Annotations.
25   * The visitors are not writing any bytecode and using a Null ClassVisitor / Code Visitor as a target instead.
26   *
27   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
28   */
29  public class AsmAnnotationHelper {
30  
31      private final static String INIT_METHOD_NAME = "<init>";
32  
33      public final static ClassVisitor NULL_CLASS_VISITOR = new NullClassVisitor();
34  
35      public static final Attribute[] ANNOTATIONS_ATTRIBUTES = new Attribute[]{
36          new RuntimeInvisibleAnnotations(),
37          new RuntimeVisibleAnnotations()
38      };
39  
40      /***
41       * Generic extractor
42       */
43      private static class AnnotationExtractor extends NullClassVisitor {
44  
45          /***
46           * The list where encountered annotation will be put
47           */
48          protected List m_annotations;
49  
50          /***
51           * This classloader will be used to instantiate the proxy instance for Custom Annotation support (1.3/1.4).
52           * See CustomAttribute that wraps in a RuntimeInvisibleAnnotation the user custom annotations.
53           * <br/>Note: no weak reference is used since the visitor is created for a one shot usage.
54           */
55          protected ClassLoader m_loader;
56  
57          /***
58           * Generic extractor
59           *
60           * @param annotations list where to put annotations
61           * @param loader classLoader used to instantiate proxy of custom annotations
62           */
63          private AnnotationExtractor(List annotations, final ClassLoader loader) {
64              m_annotations = annotations;
65              m_loader = loader;
66          }
67      }
68  
69      /***
70       * Extracts class level annotations
71       */
72      public static class ClassAnnotationExtractor extends AnnotationExtractor {
73  
74          public ClassAnnotationExtractor(List annotations, final ClassLoader loader) {
75              super(annotations, loader);
76          }
77  
78          public void visitAttribute(final Attribute attribute) {
79              m_annotations = extractAnnotations(m_annotations, attribute, m_loader);
80              super.visitAttribute(attribute);
81          }
82      }
83  
84      /***
85       * Generic extractor for member (ctor, method, field) annotations extraction
86       */
87      private static class MemberAnnotationExtractor extends AnnotationExtractor {
88  
89          /***
90           * Member name (method name, "<init>", field name
91           */
92          protected String m_name;
93  
94          /***
95           * Member descriptor (as in visitMethod/visitField ASM methods)
96           */
97          protected String m_desc;
98  
99          /***
100          * Method annotation extractor
101          * @param annotations
102          * @param name of the member for which we want the annotations
103          * @param desc of the member for which we want the annotations
104          * @param loader
105          */
106         private MemberAnnotationExtractor(List annotations, String name, String desc, final ClassLoader loader) {
107             super(annotations, loader);
108             m_name = name;
109             m_desc = desc;
110         }
111     }
112 
113     /***
114      * Method annotations extractor
115      */
116     public static class MethodAnnotationExtractor extends MemberAnnotationExtractor {
117 
118         public MethodAnnotationExtractor(List annotations, String name, String desc, final ClassLoader loader) {
119             super(annotations, name, desc, loader);
120         }
121 
122         public CodeVisitor visitMethod(final int access,
123                                        final String name,
124                                        final String desc,
125                                        final String[] exceptions,
126                                        final Attribute attrs) {
127             if (name.equals(m_name) && desc.equals(m_desc)) {
128                 m_annotations = extractAnnotations(m_annotations, attrs, m_loader);
129             }
130             return super.visitMethod(access, name, desc, exceptions, attrs);
131         }
132     }
133 
134     /***
135      * Constructor annotations extractor
136      */
137     public static class ConstructorAnnotationExtractor extends MethodAnnotationExtractor {
138 
139         public ConstructorAnnotationExtractor(List annotations, String desc, final ClassLoader loader) {
140             super(annotations, INIT_METHOD_NAME, desc, loader);
141         }
142     }
143 
144     /***
145      * Field annotations extractor
146      */
147     public static class FieldAnnotationExtractor extends MemberAnnotationExtractor {
148 
149         public FieldAnnotationExtractor(List annotations, String name, final ClassLoader loader) {
150             super(annotations, name, null, loader);
151         }
152 
153         public void visitField (final int access,
154           final String name,
155           final String desc,
156           final Object value,
157           final Attribute attrs) {
158             // no match on desc
159             if (name.equals(m_name)) {
160                 m_annotations = extractAnnotations(m_annotations, attrs, m_loader);
161             }
162             super.visitField(access, name, desc, value, attrs);
163         }
164     }
165 
166     /***
167      * A NullClassVisitor that does nothing.
168      * Can be used to speed up ASM and avoid unecessary bytecode writing thru a regular ClassWriter when this is not
169      * needed (read only purpose).
170      */
171     private static class NullClassVisitor implements ClassVisitor {
172 
173         public void visit(int i, int i1, String s, String s1, String[] strings, String s2) {
174         }
175 
176         public void visitInnerClass(String s, String s1, String s2, int i) {
177         }
178 
179         public void visitField(int i, String s, String s1, Object o, Attribute attribute) {
180         }
181 
182         public CodeVisitor visitMethod(int i, String s, String s1, String[] strings, Attribute attribute) {
183             return NullCodeVisitor.NULL_CODE_VISITOR;
184         }
185 
186         public void visitAttribute(Attribute attribute) {
187         }
188 
189         public void visitEnd() {
190         }
191     }
192 
193     /***
194      * A NullCodeVisitor that does nothing.
195      * Can be used to speed up ASM and avoid unecessary bytecode writing thru a regular CodeWriter when this is not
196      * needed (read only purpose)
197      */
198     private static class NullCodeVisitor implements CodeVisitor {
199 
200         private final static CodeVisitor NULL_CODE_VISITOR = new NullCodeVisitor();
201 
202         public void visitInsn(int opcode) {
203         }
204 
205         public void visitIntInsn(int opcode, int operand) {
206         }
207 
208         public void visitVarInsn(int opcode, int var) {
209         }
210 
211         public void visitTypeInsn(int opcode, String desc) {
212         }
213 
214         public void visitFieldInsn(int opcode, String owner, String name, String desc) {
215         }
216 
217         public void visitMethodInsn(int opcode, String owner, String name, String desc) {
218         }
219 
220         public void visitJumpInsn(int opcode, Label label) {
221         }
222 
223         public void visitLabel(Label label) {
224         }
225 
226         public void visitLdcInsn(Object cst) {
227         }
228 
229         public void visitIincInsn(int var, int increment) {
230         }
231 
232         public void visitTableSwitchInsn(int min, int max, Label dflt, Label labels[]) {
233         }
234 
235         public void visitLookupSwitchInsn(Label dflt, int keys[], Label labels[]) {
236         }
237 
238         public void visitMultiANewArrayInsn(String desc, int dims) {
239         }
240 
241         public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
242         }
243 
244         public void visitMaxs(int maxStack, int maxLocals) {
245         }
246 
247         public void visitLocalVariable(String name, String desc, Label start, Label end, int index) {
248         }
249 
250         public void visitLineNumber(int line, Label start) {
251         }
252 
253         public void visitAttribute(Attribute attr) {
254         }
255     }
256 
257     /***
258      * Helper method to extract Runtime(In)VisibleAnnotations and unwrap custom annotation proxies
259      *
260      * @param annotations
261      * @param attribute
262      * @param loader
263      * @return annotations list populated
264      */
265     public static List extractAnnotations(List annotations, final Attribute attribute, final ClassLoader loader) {
266         for (Attribute current = attribute; current != null; current = current.next) {
267             if (current instanceof RuntimeInvisibleAnnotations) {
268                 for (Iterator it = ((RuntimeInvisibleAnnotations) current).annotations.iterator(); it.hasNext();) {
269                     Annotation annotation = (Annotation) it.next();
270                     if (CustomAttribute.TYPE.equals(annotation.type)) {
271                         annotations.add(CustomAttributeHelper.extractCustomAnnotation(annotation));
272                     } else {
273                         AnnotationInfo annotationInfo = AsmClassInfo.getAnnotationInfo(
274                                 annotation,
275                                 loader
276                         );
277                         annotations.add(annotationInfo);
278                     }
279                 }
280             } else if (current instanceof RuntimeVisibleAnnotations) {
281                 for (Iterator it = ((RuntimeVisibleAnnotations) current).annotations.iterator(); it.hasNext();) {
282                     Annotation annotation = (Annotation) it.next();
283                     AnnotationInfo annotationInfo = AsmClassInfo.getAnnotationInfo(
284                             annotation,
285                             loader
286                     );
287                     annotations.add(annotationInfo);
288                 }
289             }
290         }
291         return annotations;
292     }
293 }