001: /**************************************************************************************
002: * Copyright (c) Jonas Bon?r, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.annotation.instrumentation.asm;
008:
009: import org.objectweb.asm.ClassVisitor;
010: import org.objectweb.asm.Attribute;
011: import org.objectweb.asm.CodeVisitor;
012: import org.objectweb.asm.Label;
013: import org.objectweb.asm.Type;
014: import org.objectweb.asm.attrs.RuntimeInvisibleAnnotations;
015: import org.objectweb.asm.attrs.Annotation;
016: import org.objectweb.asm.attrs.RuntimeVisibleAnnotations;
017: import org.objectweb.asm.attrs.AnnotationDefaultAttribute;
018: import org.objectweb.asm.attrs.Attributes;
019: import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
020: import org.codehaus.aspectwerkz.annotation.AnnotationDefault;
021: import org.codehaus.aspectwerkz.annotation.Java5AnnotationInvocationHandler;
022:
023: import java.util.List;
024: import java.util.Iterator;
025:
026: /**
027: * Helper visitor to extract Annotations.
028: * The visitors are not writing any bytecode and using a Null ClassVisitor / Code Visitor as a target instead.
029: *
030: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
031: */
032: public class AsmAnnotationHelper {
033:
034: private final static String INIT_METHOD_NAME = "<init>";
035:
036: /**
037: * Generic extractor
038: */
039: private static class AnnotationExtractor extends NullClassAdapter {
040:
041: /**
042: * The list where encountered annotation will be put
043: */
044: protected List m_annotations;
045:
046: /**
047: * This classloader will be used to instantiate the proxy instance for Custom Annotation support (1.3/1.4).
048: * See CustomAttribute that wraps in a RuntimeInvisibleAnnotation the user custom annotations.
049: * <br/>Note: no weak reference is used since the visitor is created for a one shot usage.
050: */
051: protected ClassLoader m_loader;
052:
053: /**
054: * Generic extractor
055: *
056: * @param annotations list where to put annotations
057: * @param loader classLoader used to instantiate proxy of custom annotations
058: */
059: private AnnotationExtractor(List annotations,
060: final ClassLoader loader) {
061: m_annotations = annotations;
062: m_loader = loader;
063: }
064: }
065:
066: /**
067: * Extracts class level annotations
068: */
069: public static class ClassAnnotationExtractor extends
070: AnnotationExtractor {
071:
072: public ClassAnnotationExtractor(List annotations,
073: final ClassLoader loader) {
074: super (annotations, loader);
075: }
076:
077: public void visitAttribute(final Attribute attribute) {
078: m_annotations = extractAnnotations(m_annotations,
079: attribute, m_loader);
080: super .visitAttribute(attribute);
081: }
082: }
083:
084: /**
085: * Generic extractor for member (ctor, method, field) annotations extraction
086: */
087: private static class MemberAnnotationExtractor extends
088: AnnotationExtractor {
089:
090: /**
091: * Member name (method name, "<init>", field name
092: */
093: protected String m_name;
094:
095: /**
096: * Member descriptor (as in visitMethod/visitField ASM methods)
097: */
098: protected String m_desc;
099:
100: /**
101: * Method annotation extractor
102: *
103: * @param annotations
104: * @param name of the member for which we want the annotations
105: * @param desc of the member for which we want the annotations
106: * @param loader
107: */
108: private MemberAnnotationExtractor(List annotations,
109: String name, String desc, final ClassLoader loader) {
110: super (annotations, loader);
111: m_name = name;
112: m_desc = desc;
113: }
114: }
115:
116: /**
117: * Method annotations extractor
118: */
119: public static class MethodAnnotationExtractor extends
120: MemberAnnotationExtractor {
121:
122: public MethodAnnotationExtractor(List annotations, String name,
123: String desc, final ClassLoader loader) {
124: super (annotations, name, desc, loader);
125: }
126:
127: public CodeVisitor visitMethod(final int access,
128: final String name, final String desc,
129: final String[] exceptions, final Attribute attrs) {
130: if (name.equals(m_name) && desc.equals(m_desc)) {
131: m_annotations = extractAnnotations(m_annotations,
132: attrs, m_loader);
133: }
134: return super .visitMethod(access, name, desc, exceptions,
135: attrs);
136: }
137: }
138:
139: /**
140: * Constructor annotations extractor
141: */
142: public static class ConstructorAnnotationExtractor extends
143: MethodAnnotationExtractor {
144:
145: public ConstructorAnnotationExtractor(List annotations,
146: String desc, final ClassLoader loader) {
147: super (annotations, INIT_METHOD_NAME, desc, loader);
148: }
149: }
150:
151: /**
152: * Field annotations extractor
153: */
154: public static class FieldAnnotationExtractor extends
155: MemberAnnotationExtractor {
156:
157: public FieldAnnotationExtractor(List annotations, String name,
158: final ClassLoader loader) {
159: super (annotations, name, null, loader);
160: }
161:
162: public void visitField(final int access, final String name,
163: final String desc, final Object value,
164: final Attribute attrs) {
165: // no match on desc
166: if (name.equals(m_name)) {
167: m_annotations = extractAnnotations(m_annotations,
168: attrs, m_loader);
169: }
170: super .visitField(access, name, desc, value, attrs);
171: }
172: }
173:
174: /**
175: * A NullClassAdapter that does nothing.
176: * Can be used to speed up ASM and avoid unecessary bytecode writing thru a regular ClassWriter when this is not
177: * needed (read only purpose).
178: */
179: public static class NullClassAdapter implements ClassVisitor {
180:
181: public final static ClassVisitor NULL_CLASS_ADAPTER = new NullClassAdapter();
182:
183: public void visit(int i, int i1, String s, String s1,
184: String[] strings, String s2) {
185: }
186:
187: public void visitInnerClass(String s, String s1, String s2,
188: int i) {
189: }
190:
191: public void visitField(int i, String s, String s1, Object o,
192: Attribute attribute) {
193: }
194:
195: public CodeVisitor visitMethod(int i, String s, String s1,
196: String[] strings, Attribute attribute) {
197: return NullCodeAdapter.NULL_CODE_ADAPTER;
198: }
199:
200: public void visitAttribute(Attribute attribute) {
201: }
202:
203: public void visitEnd() {
204: }
205: }
206:
207: /**
208: * A NullCodeAdapter that does nothing.
209: * Can be used to speed up ASM and avoid unecessary bytecode writing thru a regular CodeWriter when this is not
210: * needed (read only purpose)
211: */
212: public static class NullCodeAdapter implements CodeVisitor {
213:
214: public final static CodeVisitor NULL_CODE_ADAPTER = new NullCodeAdapter();
215:
216: public void visitInsn(int opcode) {
217: }
218:
219: public void visitIntInsn(int opcode, int operand) {
220: }
221:
222: public void visitVarInsn(int opcode, int var) {
223: }
224:
225: public void visitTypeInsn(int opcode, String desc) {
226: }
227:
228: public void visitFieldInsn(int opcode, String owner,
229: String name, String desc) {
230: }
231:
232: public void visitMethodInsn(int opcode, String owner,
233: String name, String desc) {
234: }
235:
236: public void visitJumpInsn(int opcode, Label label) {
237: }
238:
239: public void visitLabel(Label label) {
240: }
241:
242: public void visitLdcInsn(Object cst) {
243: }
244:
245: public void visitIincInsn(int var, int increment) {
246: }
247:
248: public void visitTableSwitchInsn(int min, int max, Label dflt,
249: Label labels[]) {
250: }
251:
252: public void visitLookupSwitchInsn(Label dflt, int keys[],
253: Label labels[]) {
254: }
255:
256: public void visitMultiANewArrayInsn(String desc, int dims) {
257: }
258:
259: public void visitTryCatchBlock(Label start, Label end,
260: Label handler, String type) {
261: }
262:
263: public void visitMaxs(int maxStack, int maxLocals) {
264: }
265:
266: public void visitLocalVariable(String name, String desc,
267: Label start, Label end, int index) {
268: }
269:
270: public void visitLineNumber(int line, Label start) {
271: }
272:
273: public void visitAttribute(Attribute attr) {
274: }
275: }
276:
277: /**
278: * Helper method to extract Runtime(In)VisibleAnnotations and unwrap custom annotation proxies
279: *
280: * @param annotations
281: * @param attribute
282: * @param loader
283: * @return annotations list populated
284: */
285: public static List extractAnnotations(List annotations,
286: final Attribute attribute, final ClassLoader loader) {
287: for (Attribute current = attribute; current != null; current = current.next) {
288: if (current instanceof RuntimeInvisibleAnnotations) {
289: for (Iterator it = ((RuntimeInvisibleAnnotations) current).annotations
290: .iterator(); it.hasNext();) {
291: Annotation annotation = (Annotation) it.next();
292: if (CustomAttribute.TYPE.equals(annotation.type)) {
293: annotations.add(CustomAttributeHelper
294: .extractCustomAnnotation(annotation));
295: } else {
296: AnnotationInfo annotationInfo = getAnnotationInfo(
297: annotation, loader);
298: annotations.add(annotationInfo);
299: }
300: }
301: } else if (current instanceof RuntimeVisibleAnnotations) {
302: for (Iterator it = ((RuntimeVisibleAnnotations) current).annotations
303: .iterator(); it.hasNext();) {
304: Annotation annotation = (Annotation) it.next();
305: AnnotationInfo annotationInfo = getAnnotationInfo(
306: annotation, loader);
307: annotations.add(annotationInfo);
308: }
309: } else if (current instanceof AnnotationDefaultAttribute) {
310: AnnotationDefaultAttribute defaultAttribute = (AnnotationDefaultAttribute) current;
311: AnnotationInfo annotationInfo = new AnnotationInfo(
312: AnnotationDefault.NAME,
313: new AnnotationDefault.AnnotationDefaultImpl(
314: defaultAttribute.defaultValue));
315: annotations.add(annotationInfo);
316: }
317: }
318: return annotations;
319: }
320:
321: /**
322: * Creates and returns a new annotation info build up from the Java5 annotation.
323: *
324: * @param annotation the ASM annotation abstraction
325: * @param loader the class loader that has loaded the proxy class to use
326: * @return the annotation info
327: */
328: public static AnnotationInfo getAnnotationInfo(
329: final Annotation annotation, final ClassLoader loader) {
330: String annotationName = Type.getType(annotation.type)
331: .getClassName();
332: return new AnnotationInfo(annotationName,
333: Java5AnnotationInvocationHandler.getAnnotationProxy(
334: annotation, loader));
335: }
336: }
|