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
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 }