KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > backport175 > bytecode > AnnotationReader


1 /*******************************************************************************************
2  * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
3  * http://backport175.codehaus.org *
4  * --------------------------------------------------------------------------------------- *
5  * The software in this package is published under the terms of Apache License Version 2.0 *
6  * a copy of which has been included with this distribution in the license.txt file. *
7  *******************************************************************************************/

8 package com.tc.backport175.bytecode;
9
10 import com.tc.backport175.Annotation;
11 //import com.tc.backport175.ReaderException;
12
import com.tc.backport175.bytecode.spi.BytecodeProvider;
13 import com.tc.backport175.proxy.ProxyFactory;
14
15 import com.tc.asm.AnnotationVisitor;
16 import com.tc.asm.Attribute;
17 import com.tc.asm.ClassAdapter;
18 import com.tc.asm.ClassReader;
19 import com.tc.asm.ClassVisitor;
20 import com.tc.asm.ClassWriter;
21 import com.tc.asm.FieldVisitor;
22 import com.tc.asm.MethodAdapter;
23 import com.tc.asm.MethodVisitor;
24 import com.tc.asm.Type;
25
26 import java.lang.ref.Reference JavaDoc;
27 import java.lang.ref.WeakReference JavaDoc;
28 import java.lang.reflect.Constructor JavaDoc;
29 import java.lang.reflect.Field JavaDoc;
30 import java.lang.reflect.Method JavaDoc;
31 import java.util.Collection JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.WeakHashMap JavaDoc;
36
37 /**
38  * Reads Java 5 {@link java.lang.annotation.RetentionPolicy.RUNTIME} and
39  * {@link java.lang.annotation.RetentionPolicy.CLASS} annotations from the class' bytecode.
40  * <p/>
41  * Can be used with a custom implementation of the {@link org.codehaus.backport175.reader.bytecode.spi.BytecodeProvider}
42  * interface.
43  * <p/>
44  * Note: does not handles {@link java.lang.annotation.Inherited} feature. This has to be done in the higher level
45  * that knows about the class hierarchy (see backport175.Annotations f.e)
46  *
47  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér</a>
48  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
49  */

50 public class AnnotationReader {
51
52     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
53     private static final AnnotationElement.Annotation[] EMPTY_ANNOTATION_ELEMENT_ARRAY =
54             new AnnotationElement.Annotation[0];
55     private static final String JavaDoc INIT_METHOD_NAME = "<init>";
56
57     private static final Map JavaDoc CLASS_SPECIFIC_BYTECODE_PROVIDER = new WeakHashMap JavaDoc();
58     private static BytecodeProvider BYTECODE_PROVIDER = new DefaultBytecodeProvider();
59
60     /**
61      * Key is ClassKey, value is WeakReference of AnnotationReader
62      */

63     private static final Map JavaDoc READERS = new WeakHashMap JavaDoc();
64
65     private final ClassKey m_classKey;
66
67     // ===========================================================================
68
// Implementation notes:
69
// Parsing and annotation creation is made in two steps
70
//
71
// 1. The bytecode is parsed and the annotation content is put in elements,
72
// which are stored for later processing
73
//
74
// 2. Upon annotation access the elements are processed and a dynamic proxy
75
// for the annotation is created and cached.
76
//
77
// This gives much better performance than reflective access of Java 5
78
// annotations (reflective access is around 5 times slower)
79
// ===========================================================================
80

81     private final Map JavaDoc m_classAnnotationElements = new HashMap JavaDoc();
82     private final Map JavaDoc m_constructorAnnotationElements = new HashMap JavaDoc();
83     private final Map JavaDoc m_methodAnnotationElements = new HashMap JavaDoc();
84     private final Map JavaDoc m_fieldAnnotationElements = new HashMap JavaDoc();
85
86     private final Map JavaDoc m_classAnnotationCache = new HashMap JavaDoc();
87     private final Map JavaDoc m_constructorAnnotationCache = new HashMap JavaDoc();
88     private final Map JavaDoc m_methodAnnotationCache = new HashMap JavaDoc();
89     private final Map JavaDoc m_fieldAnnotationCache = new HashMap JavaDoc();
90
91     /**
92      * Sets the bytecode provider.
93      * <p/>
94      * If a custom provider is not set then a default impl will be used (which reads the bytecode from disk).
95      *
96      * @param bytecodeProvider
97      */

98     public static void setDefaultBytecodeProvider(final BytecodeProvider bytecodeProvider) {
99         BYTECODE_PROVIDER = bytecodeProvider;
100     }
101
102     /**
103      * Returns the bytecode provider.
104      *
105      * @return the bytecode provider
106      */

107     public static BytecodeProvider getDefaultBytecodeProvider() {
108         return BYTECODE_PROVIDER;
109     }
110
111     /**
112      * Sets the bytecode provider.
113      * <p/>
114      * If a custom provider is not set then a default impl will be used (which reads the bytecode from disk).
115      *
116      * @param klass
117      * @param bytecodeProvider
118      */

119     public static void setBytecodeProviderFor(final Class JavaDoc klass, final BytecodeProvider bytecodeProvider) {
120         setBytecodeProviderFor(klass.getName(), klass.getClassLoader(), bytecodeProvider);
121     }
122
123     /**
124      * Sets the bytecode provider.
125      * <p/>
126      * If a custom provider is not set then a default impl will be used (which reads the bytecode from disk).
127      *
128      * @param className
129      * @param loader
130      * @param bytecodeProvider
131      */

132     public static void setBytecodeProviderFor(final String JavaDoc className,
133                                               final ClassLoader JavaDoc loader,
134                                               final BytecodeProvider bytecodeProvider) {
135         CLASS_SPECIFIC_BYTECODE_PROVIDER.put(new ClassKey(className, loader), bytecodeProvider);
136     }
137
138     /**
139      * Returns the bytecode provider.
140      *
141      * @param klass
142      * @return the bytecode provider
143      */

144     public static BytecodeProvider getBytecodeProviderFor(final Class JavaDoc klass) {
145         return getBytecodeProviderFor(klass.getName(), klass.getClassLoader());
146     }
147
148     /**
149      * Returns the bytecode provider.
150      *
151      * @param className
152      * @param loader
153      * @return the bytecode provider
154      */

155     public static BytecodeProvider getBytecodeProviderFor(final String JavaDoc className, final ClassLoader JavaDoc loader) {
156         BytecodeProvider bytecodeProvider = (BytecodeProvider) CLASS_SPECIFIC_BYTECODE_PROVIDER.get(
157                 new ClassKey(className, loader)
158         );
159         if (bytecodeProvider == null) {
160             return BYTECODE_PROVIDER;
161         }
162         return bytecodeProvider;
163     }
164
165     /**
166      * Returns the bytecode for a class.
167      *
168      * @param className
169      * @param loader
170      * @return the bytecode for a class
171      */

172     public static byte[] getBytecodeFor(final String JavaDoc className, final ClassLoader JavaDoc loader) throws Exception JavaDoc {
173         return getBytecodeProviderFor(className, loader).getBytecode(className, loader);
174     }
175
176     /**
177      * Returns the annotation reader for the class specified.
178      * <p/>
179      * The annotation reader is created and cached if non-existant.
180      *
181      * @param klass
182      * @return the annotation reader
183      */

184     public static AnnotationReader getReaderFor(final Class JavaDoc klass) {
185         return getReaderFor(new ClassKey(klass.getName(), klass.getClassLoader()));
186     }
187
188     /**
189      * Returns the annotation reader for the class specified.
190      * <p/>
191      * The annotation reader is created and cached if non-existant.
192      *
193      * @param className
194      * @param loader
195      * @return the annotation reader
196      */

197     public static AnnotationReader getReaderFor(final String JavaDoc className, final ClassLoader JavaDoc loader) {
198         return getReaderFor(new ClassKey(className, loader));
199     }
200
201     /**
202      * Returns the annotation reader for the class specified.
203      * <p/>
204      * The annotation reader is created and cached if non-existant.
205      *
206      * @param classKey
207      * @return the annotation reader
208      */

209     public static AnnotationReader getReaderFor(final ClassKey classKey) {
210         AnnotationReader reader;
211         Object JavaDoc value = READERS.get(classKey);
212         if (value == null) {
213             synchronized (READERS) {
214                 reader = new AnnotationReader(classKey);
215                 READERS.put(classKey, new WeakReference JavaDoc(reader));//reader strong refs its own key in the weakhahsmap..
216
}
217         } else {
218             reader = (AnnotationReader) ((Reference JavaDoc)value).get();
219             if (reader == null) {//WeakReference content can be null
220
synchronized (READERS) {
221                       reader = new AnnotationReader(classKey);
222                       READERS.put(classKey, new WeakReference JavaDoc(reader));
223                 }
224             }
225         }
226         return reader;
227     }
228
229     /**
230      * Resets the annotation reader for the class specified and triggers a new parsing of the newly read bytecode.
231      * <p/>
232      * This method calls <code>parse</code> and is therefore all the is needed to invoke to get a fully updated reader.
233      *
234      * @param klass
235      */

236     public static void refresh(final Class JavaDoc klass) {
237         AnnotationReader reader = getReaderFor(klass);
238         synchronized (reader) {
239             reader.refresh();
240         }
241     }
242
243     /**
244      * Resets the annotation reader for the class specified and triggers a new parsing of the newly read bytecode.
245      * <p/>
246      * This method calls <code>parse</code> and is therefore all the is needed to invoke to get a fully updated reader.
247      *
248      * @param className
249      * @param loader
250      */

251     public static void refresh(final String JavaDoc className, final ClassLoader JavaDoc loader) {
252         AnnotationReader reader = getReaderFor(className, loader);
253         synchronized (reader) {
254             reader.refresh();
255         }
256     }
257
258     /**
259      * Resets *all* the annotation reader and triggers a new parsing of the newly read bytecode.
260      * <p/>
261      * This method will force parsing of all classes bytecode which might be very time consuming, use with care.
262      * <p/>
263      * This method calls <code>parse</code> and is therefore all the is needed to invoke to get a fully updated reader.
264      */

265     public static void refreshAll() {
266         for (Iterator JavaDoc it = READERS.values().iterator(); it.hasNext();) {
267             AnnotationReader reader = (AnnotationReader) ((Reference JavaDoc)it.next()).get();
268             synchronized (reader) {
269                 reader.refresh();
270             }
271         }
272     }
273
274     /**
275      * Converts the annotion class description to a Java class name.
276      * Caution: Does not handles array type or primitive.
277      *
278      * @param desc
279      * @return
280      */

281     public static String JavaDoc toJavaName(final String JavaDoc desc) {
282         return desc.substring(1, desc.length() - 1).replace('/', '.');
283     }
284
285     /**
286      * Checks if an annotation is present at a specific class.
287      *
288      * @param annotationName the annotation name
289      * @return true if the annotation is present else false
290      */

291     public boolean isAnnotationPresent(final String JavaDoc annotationName) {
292         return m_classAnnotationElements.containsKey(annotationName);
293     }
294
295     /**
296      * Returns the class annotation with the name specified.
297      *
298      * @param annotationName
299      * @return the class annotation
300      */

301     public Annotation getAnnotation(final String JavaDoc annotationName) {
302         Object JavaDoc cachedAnnotation = m_classAnnotationCache.get(annotationName);
303         if (cachedAnnotation != null) {
304             return (Annotation) cachedAnnotation;
305         } else {
306             final Annotation annotation;
307             final AnnotationElement.Annotation annotationInfo =
308                     (AnnotationElement.Annotation) m_classAnnotationElements.get(annotationName);
309             if (annotationInfo != null) {
310                 annotation = ProxyFactory.newAnnotationProxy(annotationInfo, m_classKey.getClassLoader());
311                 m_classAnnotationCache.put(annotationName, annotation);
312                 return annotation;
313             } else {
314                 return null;
315             }
316         }
317     }
318
319     /**
320      * Returns all the class annotations.
321      *
322      * @return an array with the class annotations
323      */

324     public Annotation[] getAnnotations() {
325         final Collection JavaDoc annotationNames = m_classAnnotationElements.keySet();
326         if (annotationNames.isEmpty()) {
327             return EMPTY_ANNOTATION_ARRAY;
328         }
329         final Annotation[] annotations = new Annotation[annotationNames.size()];
330         int i = 0;
331         for (Iterator JavaDoc iterator = annotationNames.iterator(); iterator.hasNext();) {
332             String JavaDoc annotationName = (String JavaDoc) iterator.next();
333             annotations[i++] = getAnnotation(annotationName);
334         }
335         return annotations;
336     }
337
338     /**
339      * Checks if an annotation is present at a specific constructor.
340      *
341      * @param annotationName the annotation name
342      * @param constructor the java.lang.reflect.Constructor object to find the annotations on.
343      * @return true if the annotation is present else false
344      */

345     public boolean isAnnotationPresent(final String JavaDoc annotationName, final Constructor JavaDoc constructor) {
346         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newConstructorKey(constructor);
347         Object JavaDoc map = m_constructorAnnotationElements.get(key);
348         if (map != null) {
349             if (((Map JavaDoc) map).containsKey(annotationName)) {
350                 return true;
351             }
352         }
353         return false;
354     }
355
356     /**
357      * Returns the constructor annotation with the name specified for the constructor specified.
358      *
359      * @param annotationName the annotation name
360      * @param constructor the java.lang.reflect.Constructor object to find the annotations on.
361      * @return the constructor annotation
362      */

363     public Annotation getAnnotation(final String JavaDoc annotationName, final Constructor JavaDoc constructor) {
364         return getConstructorAnnotation(annotationName, MemberKey.newConstructorKey(constructor), constructor.getDeclaringClass().getClassLoader());
365     }
366
367     /**
368      * Returns the constructor annotation with the name specified for the constructor specified.
369      *
370      * @param annotationName
371      * @param constructorDesc
372      * @param loader
373      * @return
374      */

375     public Annotation getConstructorAnnotation(final String JavaDoc annotationName, final String JavaDoc constructorDesc, final ClassLoader JavaDoc loader) {
376         return getConstructorAnnotation(annotationName, MemberKey.newConstructorKey(constructorDesc), loader);
377     }
378
379     /**
380      * Returns the constructor annotation with the name specified for the constructor specified.
381      *
382      * @param annotationName
383      * @param constructorKey
384      * @param loader
385      * @return
386      */

387     private Annotation getConstructorAnnotation(final String JavaDoc annotationName, final MemberKey constructorKey, final ClassLoader JavaDoc loader) {
388         Map JavaDoc annotationMap = getConstructorAnnotationCacheFor(constructorKey);
389         Object JavaDoc cachedAnnotation = annotationMap.get(annotationName);
390         if (cachedAnnotation != null) {
391             return (Annotation) cachedAnnotation;
392         }
393         // not in cache - create a new DP and put in cache
394
final Map JavaDoc annotations = (Map JavaDoc) m_constructorAnnotationElements.get(constructorKey);
395         if (annotations == null) {
396             // no such annotation
397
return null;
398         }
399         Object JavaDoc annotationElement = annotations.get(annotationName);
400         if (annotationElement != null) {
401             Annotation annotation = ProxyFactory.newAnnotationProxy(
402                     (AnnotationElement.Annotation) annotationElement,
403                     loader
404             );
405             annotationMap.put(annotationName, annotation);
406             return annotation;
407         }
408         return null;
409     }
410
411     /**
412      * Returns all the constructor annotations.
413      *
414      * @param constructor the java.lang.reflect.Constructor object to find the annotations on.
415      * @return an array with the constructor annotations
416      */

417     public Annotation[] getAnnotations(final Constructor JavaDoc constructor) {
418         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newConstructorKey(constructor);
419         Object JavaDoc map = m_constructorAnnotationElements.get(key);
420         if (map != null) {
421             final Collection JavaDoc annotationNames = ((Map JavaDoc) map).keySet();
422             if (annotationNames.isEmpty()) {
423                 return EMPTY_ANNOTATION_ARRAY;
424             }
425             final Annotation[] annotations = new Annotation[annotationNames.size()];
426             int i = 0;
427             for (Iterator JavaDoc iterator = annotationNames.iterator(); iterator.hasNext();) {
428                 String JavaDoc annotationName = (String JavaDoc) iterator.next();
429                 annotations[i++] = getAnnotation(annotationName, constructor);
430             }
431             return annotations;
432         } else {
433             return EMPTY_ANNOTATION_ARRAY;
434         }
435     }
436
437     /**
438      * Checks if an annotation is present at a specific method.
439      *
440      * @param annotationName the annotation name
441      * @param method the java.lang.reflect.Method object to find the annotations on.
442      * @return true if the annotation is present else false
443      */

444     public boolean isAnnotationPresent(final String JavaDoc annotationName, final Method JavaDoc method) {
445         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newMethodKey(method);
446         Object JavaDoc map = m_methodAnnotationElements.get(key);
447         if (map != null) {
448             if (((Map JavaDoc) m_methodAnnotationElements.get(key)).containsKey(annotationName)) {
449                 return true;
450             }
451         }
452         return false;
453     }
454
455     /**
456      * Returns the method annotation with the name specified for the method specified.
457      *
458      * @param annotationName the annotation name
459      * @param method the java.lang.reflect.Method object to find the annotations on.
460      * @return the method annotation
461      */

462     public Annotation getAnnotation(final String JavaDoc annotationName, final Method JavaDoc method) {
463         return getMethodAnnotation(
464                 annotationName,
465                 MemberKey.newMethodKey(method),
466                 method.getDeclaringClass().getClassLoader()
467         );
468     }
469
470     /**
471      * Returns the method annotation with the name specified for the method specified.
472      *
473      * @param annotationName
474      * @param methodName
475      * @param methodDesc
476      * @param loader
477      * @return
478      */

479     public Annotation getMethodAnnotation(final String JavaDoc annotationName, final String JavaDoc methodName, final String JavaDoc methodDesc, final ClassLoader JavaDoc loader) {
480         return getMethodAnnotation(
481                 annotationName,
482                 MemberKey.newMethodKey(methodName, methodDesc),
483                 loader
484         );
485     }
486
487     /**
488      * Returns the method annotation with the name specified for the method specified.
489      *
490      * @param annotationName
491      * @param methodKey
492      * @param loader
493      * @return
494      */

495     private Annotation getMethodAnnotation(final String JavaDoc annotationName, final MemberKey methodKey, final ClassLoader JavaDoc loader) {
496         Map JavaDoc annotationMap = getMethodAnnotationCacheFor(methodKey);
497         Object JavaDoc cachedAnnotation = annotationMap.get(annotationName);
498         if (cachedAnnotation != null) {
499             return (Annotation) cachedAnnotation;
500         }
501         // not in cache - create a new DP and put in cache
502
final Map JavaDoc annotations = (Map JavaDoc) m_methodAnnotationElements.get(methodKey);
503         if (annotations == null) {
504             // no such annotation
505
return null;
506         }
507         Object JavaDoc annotationElement = annotations.get(annotationName);
508         if (annotationElement != null) {
509             Annotation annotation = ProxyFactory.newAnnotationProxy(
510                     (AnnotationElement.Annotation) annotationElement,
511                     loader
512             );
513             annotationMap.put(annotationName, annotation);
514             return annotation;
515         }
516         return null;
517     }
518
519     /**
520      * Returns all the method annotations.
521      *
522      * @param method the java.lang.reflect.Method object to find the annotations on.
523      * @return an array with the method annotations
524      */

525     public Annotation[] getAnnotations(final Method JavaDoc method) {
526         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newMethodKey(method);
527         Object JavaDoc map = m_methodAnnotationElements.get(key);
528         if (map != null) {
529             final Collection JavaDoc annotationNames = ((Map JavaDoc) map).keySet();
530             if (annotationNames.isEmpty()) {
531                 return EMPTY_ANNOTATION_ARRAY;
532             }
533             final Annotation[] annotations = new Annotation[annotationNames.size()];
534             int i = 0;
535             for (Iterator JavaDoc iterator = annotationNames.iterator(); iterator.hasNext();) {
536                 String JavaDoc annotationName = (String JavaDoc) iterator.next();
537                 annotations[i++] = getAnnotation(annotationName, method);
538             }
539             return annotations;
540         } else {
541             return EMPTY_ANNOTATION_ARRAY;
542         }
543     }
544
545     /**
546      * Checks if an annotation is present at a specific field.
547      *
548      * @param annotationName the annotation name
549      * @param field the java.lang.reflect.Field object to find the annotations on.
550      * @return true if the annotation is present else false
551      */

552     public boolean isAnnotationPresent(final String JavaDoc annotationName, final Field JavaDoc field) {
553         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newFieldKey(field);
554         Object JavaDoc map = m_fieldAnnotationElements.get(key);
555         if (map != null) {
556             if (((Map JavaDoc) map).containsKey(annotationName)) {
557                 return true;
558             }
559         }
560         return false;
561     }
562
563     /**
564      * Returns the field annotation with the name specified for the field specified.
565      *
566      * @param annotationName the annotation name
567      * @param field the java.lang.reflect.Field object to find the annotations on.
568      * @return the field annotation
569      */

570     public Annotation getAnnotation(final String JavaDoc annotationName, final Field JavaDoc field) {
571         return getFieldAnnotation(
572                 annotationName,
573                 MemberKey.newFieldKey(field),
574                 field.getDeclaringClass().getClassLoader()
575         );
576     }
577
578     /**
579      * Returns the field annotation with the name specified for the field specified.
580      *
581      * @param annotationName
582      * @param fieldName
583      * @param fieldDesc
584      * @param loader
585      * @return
586      */

587     public Annotation getFieldAnnotation(final String JavaDoc annotationName, final String JavaDoc fieldName, final String JavaDoc fieldDesc, final ClassLoader JavaDoc loader) {
588         return getFieldAnnotation(
589                 annotationName,
590                 MemberKey.newFieldKey(fieldName, fieldDesc),
591                 loader
592         );
593     }
594
595     /**
596      * Returns the field annotation with the name specified for the field specified.
597      *
598      * @param annotationName
599      * @param fieldKey
600      * @param loader
601      * @return
602      */

603     private Annotation getFieldAnnotation(final String JavaDoc annotationName, final MemberKey fieldKey, final ClassLoader JavaDoc loader) {
604         Map JavaDoc annotationMap = getFieldAnnotationCacheFor(fieldKey);
605         Object JavaDoc cachedAnnotation = annotationMap.get(annotationName);
606         if (cachedAnnotation != null) {
607             return (Annotation) cachedAnnotation;
608         }
609         // not in cache - create a new DP and put in cache
610
final Map JavaDoc annotations = (Map JavaDoc) m_fieldAnnotationElements.get(fieldKey);
611         if (annotations == null) {
612             // no such annotation
613
return null;
614         }
615         Object JavaDoc annotationElement = annotations.get(annotationName);
616         if (annotationElement != null) {
617             Annotation annotation = ProxyFactory.newAnnotationProxy(
618                     (AnnotationElement.Annotation) annotationElement,
619                     loader
620             );
621             annotationMap.put(annotationName, annotation);
622             return annotation;
623         }
624         return null;
625     }
626
627     /**
628      * Returns all the field annotations.
629      *
630      * @param field the java.lang.reflect.Field object to find the annotations on.
631      * @return an array with the field annotations
632      */

633     public Annotation[] getAnnotations(final Field JavaDoc field) {
634         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newFieldKey(field);
635         Object JavaDoc map = m_fieldAnnotationElements.get(key);
636         if (map != null) {
637             final Collection JavaDoc annotationNames = ((Map JavaDoc) map).keySet();
638             if (annotationNames.isEmpty()) {
639                 return EMPTY_ANNOTATION_ARRAY;
640             }
641             final Annotation[] annotations = new Annotation[annotationNames.size()];
642             int i = 0;
643             for (Iterator JavaDoc iterator = annotationNames.iterator(); iterator.hasNext();) {
644                 String JavaDoc annotationName = (String JavaDoc) iterator.next();
645                 annotations[i++] = getAnnotation(annotationName, field);
646             }
647             return annotations;
648         } else {
649             return EMPTY_ANNOTATION_ARRAY;
650         }
651     }
652
653     /**
654      * Returns the class annotation element with the name specified.
655      *
656      * @param annotationName
657      * @return the class annotation
658      */

659     public AnnotationElement.Annotation getAnnotationElement(final String JavaDoc annotationName) {
660         return (AnnotationElement.Annotation) m_classAnnotationElements.get(annotationName);
661     }
662
663     /**
664      * Returns all the class annotations.
665      *
666      * @return an array with the class annotations
667      */

668     public AnnotationElement.Annotation[] getAnnotationElements() {
669         final Collection JavaDoc annotations = m_classAnnotationElements.values();
670         if (annotations.isEmpty()) {
671             return EMPTY_ANNOTATION_ELEMENT_ARRAY;
672         }
673         return createAnnotationElementArray(annotations);
674     }
675
676     /**
677      * Checks if an annotation is present at a specific constructor.
678      *
679      * @param annotationName the annotation name
680      * @param desc the constructor desc
681      * @return true if the annotation is present else false
682      */

683     public boolean isConstructorAnnotationPresent(final String JavaDoc annotationName, final String JavaDoc desc) {
684         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newConstructorKey(desc);
685         Object JavaDoc map = m_constructorAnnotationElements.get(key);
686         if (map != null) {
687             if (((Map JavaDoc) map).containsKey(annotationName)) {
688                 return true;
689             }
690         }
691         return false;
692     }
693
694     /**
695      * Returns the annotation with the name specified for the constructor specified.
696      *
697      * @param annotationName the annotation name
698      * @param desc the constructor desc
699      * @return the constructor annotation element
700      */

701     public AnnotationElement.Annotation getConstructorAnnotationElement(final String JavaDoc annotationName, final String JavaDoc desc) {
702         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newConstructorKey(desc);
703         final Map JavaDoc annotations = (Map JavaDoc) m_constructorAnnotationElements.get(key);
704         if (annotations == null) {
705             // no such annotation
706
return null;
707         }
708         return (AnnotationElement.Annotation) annotations.get(annotationName);
709     }
710
711     /**
712      * Returns all the constructor annotation elements.
713      *
714      * @param desc the constructor desc
715      * @return an array with the constructor annotation elements
716      */

717     public AnnotationElement.Annotation[] getConstructorAnnotationElements(final String JavaDoc desc) {
718         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newConstructorKey(desc);
719         Object JavaDoc map = m_constructorAnnotationElements.get(key);
720         if (map != null) {
721             final Collection JavaDoc annotations = ((Map JavaDoc) map).values();
722             if (annotations.isEmpty()) {
723                 return EMPTY_ANNOTATION_ELEMENT_ARRAY;
724             }
725             return createAnnotationElementArray(annotations);
726         } else {
727             return EMPTY_ANNOTATION_ELEMENT_ARRAY;
728         }
729     }
730
731     /**
732      * Checks if an annotation is present at a specific method.
733      *
734      * @param annotationName the annotation name
735      * @param name the method name
736      * @param desc the method desc
737      * @return true if the annotation is present else false
738      */

739     public boolean isMethodAnnotationPresent(final String JavaDoc annotationName, final String JavaDoc name, final String JavaDoc desc) {
740         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newMethodKey(name, desc);
741         Object JavaDoc map = m_methodAnnotationElements.get(key);
742         if (map != null) {
743             if (((Map JavaDoc) map).containsKey(annotationName)) {
744                 return true;
745             }
746         }
747         return false;
748     }
749
750     /**
751      * Returns the method annotation with the name specified for the method specified.
752      *
753      * @param annotationName the annotation name
754      * @param name the method name
755      * @param desc the method desc
756      * @return the method annotation element
757      */

758     public AnnotationElement.Annotation getMethodAnnotationElement(final String JavaDoc annotationName,
759                                                                    final String JavaDoc name,
760                                                                    final String JavaDoc desc) {
761         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newMethodKey(name, desc);
762         final Map JavaDoc annotations = (Map JavaDoc) m_methodAnnotationElements.get(key);
763         if (annotations == null) {
764             // no such annotation
765
return null;
766         }
767         return (AnnotationElement.Annotation) annotations.get(annotationName);
768     }
769
770     /**
771      * Returns all the method annotation elements.
772      *
773      * @param name the method name
774      * @param desc the method desc
775      * @return an array with the method annotation elements
776      */

777     public AnnotationElement.Annotation[] getMethodAnnotationElements(final String JavaDoc name, final String JavaDoc desc) {
778         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newMethodKey(name, desc);
779         Object JavaDoc map = m_methodAnnotationElements.get(key);
780         if (map != null) {
781             final Collection JavaDoc annotations = ((Map JavaDoc) m_methodAnnotationElements.get(key)).values();
782             if (annotations.isEmpty()) {
783                 return EMPTY_ANNOTATION_ELEMENT_ARRAY;
784             }
785             return createAnnotationElementArray(annotations);
786         } else {
787             return EMPTY_ANNOTATION_ELEMENT_ARRAY;
788         }
789     }
790
791     /**
792      * Checks if an annotation is present at a specific field.
793      *
794      * @param annotationName the annotation name
795      * @param name the field name
796      * @param desc the field desc
797      * @return true if the annotation is present else false
798      */

799     public boolean isFieldAnnotationPresent(final String JavaDoc annotationName, final String JavaDoc name, final String JavaDoc desc) {
800         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newFieldKey(name, desc);
801         Object JavaDoc map = m_fieldAnnotationElements.get(key);
802         if (map != null) {
803             if (((Map JavaDoc) map).containsKey(annotationName)) {
804                 return true;
805             }
806         }
807         return false;
808     }
809
810     /**
811      * Returns the annotation with the name specified for the field specified.
812      *
813      * @param annotationName the annotation name
814      * @param name the field name
815      * @param desc the field desc
816      * @return the field annotation element
817      */

818     public AnnotationElement.Annotation getFieldAnnotationElement(final String JavaDoc annotationName,
819                                                                   final String JavaDoc name,
820                                                                   final String JavaDoc desc) {
821         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newFieldKey(name, desc);
822         final Map JavaDoc annotations = (Map JavaDoc) m_fieldAnnotationElements.get(key);
823         if (annotations == null) {
824             // no such annotation
825
return null;
826         }
827         return (AnnotationElement.Annotation) annotations.get(annotationName);
828     }
829
830     /**
831      * Returns all the field annotation elements.
832      *
833      * @param name the field name
834      * @param desc the field desc
835      * @return an array with the field annotation elements
836      */

837     public AnnotationElement.Annotation[] getFieldAnnotationElements(final String JavaDoc name, final String JavaDoc desc) {
838         final AnnotationReader.MemberKey key = AnnotationReader.MemberKey.newFieldKey(name, desc);
839         Object JavaDoc map = m_fieldAnnotationElements.get(key);
840         if (map != null) {
841             final Collection JavaDoc annotations = ((Map JavaDoc) m_fieldAnnotationElements.get(key)).values();
842             if (annotations.isEmpty()) {
843                 return EMPTY_ANNOTATION_ELEMENT_ARRAY;
844             }
845             return createAnnotationElementArray(annotations);
846         } else {
847             return EMPTY_ANNOTATION_ELEMENT_ARRAY;
848         }
849     }
850
851     /**
852      * Creates an annotation element array.
853      *
854      * @param annotations the collection with elements
855      * @return the array
856      */

857     private AnnotationElement.Annotation[] createAnnotationElementArray(final Collection JavaDoc annotations) {
858         int i = 0;
859         final AnnotationElement.Annotation[] elementArray = new AnnotationElement.Annotation[annotations.size()];
860         for (Iterator JavaDoc it = annotations.iterator(); it.hasNext();) {
861             elementArray[i++] = (AnnotationElement.Annotation) it.next();
862         }
863         return elementArray;
864     }
865
866     /**
867      * Returns the annotation cache for a specific constructor.
868      *
869      * @param constructor the constructor
870      * @return the cache
871      */

872     private Map JavaDoc getConstructorAnnotationCacheFor(final MemberKey constructor) {
873         Map JavaDoc annotationMap = (Map JavaDoc) m_constructorAnnotationCache.get(constructor);
874         if (annotationMap == null) {
875             annotationMap = new HashMap JavaDoc();
876             m_constructorAnnotationCache.put(constructor, annotationMap);
877         }
878         return annotationMap;
879     }
880
881     /**
882      * Returns the annotation cache for a specific method.
883      *
884      * @param method the method
885      * @return the cache
886      */

887     private Map JavaDoc getMethodAnnotationCacheFor(final MemberKey method) {
888         Map JavaDoc annotationMap = (Map JavaDoc) m_methodAnnotationCache.get(method);
889         if (annotationMap == null) {
890             annotationMap = new HashMap JavaDoc();
891             m_methodAnnotationCache.put(method, annotationMap);
892         }
893         return annotationMap;
894     }
895
896     /**
897      * Returns the annotation cache for a specific field.
898      *
899      * @param field the field
900      * @return the cache
901      */

902     private Map JavaDoc getFieldAnnotationCacheFor(final MemberKey field) {
903         Map JavaDoc annotationMap = (Map JavaDoc) m_fieldAnnotationCache.get(field);
904         if (annotationMap == null) {
905             annotationMap = new HashMap JavaDoc();
906             m_fieldAnnotationCache.put(field, annotationMap);
907         }
908         return annotationMap;
909     }
910
911     /**
912      * Resets the annotation reader and triggers a new parsing of the newly read bytecode.
913      * <p/>
914      * This method calls <code>parse</code> and is therefore all the is needed to invoke to get a fully updated reader.
915      */

916     private void refresh() {
917         m_classAnnotationElements.clear();
918         m_constructorAnnotationElements.clear();
919         m_methodAnnotationElements.clear();
920         m_fieldAnnotationElements.clear();
921         m_classAnnotationCache.clear();
922         m_constructorAnnotationCache.clear();
923         m_methodAnnotationCache.clear();
924         m_fieldAnnotationCache.clear();
925         AnnotationDefaults.refresh(m_classKey);
926         parse(m_classKey);
927     }
928
929     /**
930      * Parses the class bytecode and retrieves the annotations.
931      *
932      * @param classKey
933      */

934     private void parse(final ClassKey classKey) {
935         final String JavaDoc className = classKey.getName();
936         final ClassLoader JavaDoc loader = classKey.getClassLoader();
937         final byte[] bytes;
938         try {
939             bytes = getBytecodeFor(className, loader);
940         } catch (Exception JavaDoc e) {
941           e.printStackTrace();
942           return;
943 // throw new ReaderException(
944
// "could not retrieve the bytecode for class [" + className + "]", e
945
// );
946
}
947         ClassReader classReader = new ClassReader(bytes);
948         ClassWriter writer = new ClassWriter(true);
949         classReader.accept(new AnnotationRetrievingVisitor(writer), false);
950     }
951
952     /**
953      * Creates a new instance of the annotation reader, reads from the class specified.
954      *
955      * @param classKey
956      */

957     private AnnotationReader(final ClassKey classKey) {
958         if (classKey == null) {
959             throw new IllegalArgumentException JavaDoc("class info can not be null");
960         }
961         m_classKey = classKey;
962         parse(classKey);
963     }
964
965     /**
966      * Retrieves the Java 5 RuntimeVisibleAnnotations annotations from the class bytecode.
967      *
968      * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
969      */

970     private class AnnotationRetrievingVisitor extends ClassAdapter {
971
972         public AnnotationRetrievingVisitor(final ClassVisitor cv) {
973             super(cv);
974         }
975
976         public AnnotationVisitor visitAnnotation(final String JavaDoc desc, final boolean visible) {
977             cv.visitAnnotation(desc, visible);
978             String JavaDoc annotationClassName = toJavaName(desc);
979             final AnnotationElement.Annotation annotation = new AnnotationElement.Annotation(annotationClassName);
980             m_classAnnotationElements.put(annotationClassName, annotation);
981             return createAnnotationVisitor(annotation);
982         }
983
984         public FieldVisitor visitField(final int access,
985                                        final String JavaDoc name,
986                                        final String JavaDoc desc,
987                                        final String JavaDoc signature,
988                                        final Object JavaDoc value) {
989             final FieldVisitor visitor = cv.visitField(access, name, desc, signature, value);
990
991             final MemberKey key = new MemberKey(name, desc);
992             return new AnnotationRetrievingFieldVisitor(key, visitor, AnnotationReader.this);
993         }
994
995         public MethodVisitor visitMethod(final int access,
996                                          final String JavaDoc name,
997                                          final String JavaDoc desc,
998                                          final String JavaDoc signature,
999                                          final String JavaDoc[] exceptions) {
1000            MethodVisitor visitor = cv.visitMethod(access, name, desc, signature, exceptions);
1001
1002            final MemberKey key = new MemberKey(name, desc);
1003            if (name.equals(INIT_METHOD_NAME)) {
1004                return new AnnotationRetrievingConstructorVisitor(visitor, key, AnnotationReader.this);
1005            } else {
1006                return new AnnotationRetrievingMethodVisitor(visitor, key, AnnotationReader.this);
1007            }
1008        }
1009
1010    }
1011    
1012    /**
1013     * Returns the annotation visitor to use.
1014     * <p/>
1015     * Swap to the 'tracing' visitor for simple debugging.
1016     *
1017     * @param annotation
1018     * @return
1019     */

1020    public AnnotationVisitor createAnnotationVisitor(final AnnotationElement.Annotation annotation) {
1021      return new AnnotationBuilderVisitor(annotation, m_classKey.getClassLoader(), annotation.getInterfaceName());
1022// return new TraceAnnotationVisitor();
1023
}
1024
1025    private static final class AnnotationRetrievingConstructorVisitor extends MethodAdapter {
1026      private final MemberKey key;
1027      private final AnnotationReader reader;
1028
1029      private AnnotationRetrievingConstructorVisitor(MethodVisitor mv, MemberKey key, AnnotationReader reader) {
1030        super(mv);
1031        this.key = key;
1032        this.reader = reader;
1033      }
1034
1035      public AnnotationVisitor visitAnnotation(final String JavaDoc desc, final boolean visible) {
1036          final String JavaDoc className = toJavaName(desc);
1037          final AnnotationElement.Annotation annotation = new AnnotationElement.Annotation(className);
1038          if (reader.m_constructorAnnotationElements.containsKey(key)) {
1039              ((Map JavaDoc) reader.m_constructorAnnotationElements.get(key)).put(className, annotation);
1040          } else {
1041              final Map JavaDoc annotations = new HashMap JavaDoc();
1042              annotations.put(className, annotation);
1043              reader.m_constructorAnnotationElements.put(key, annotations);
1044          }
1045          return reader.createAnnotationVisitor(annotation);
1046      }
1047    }
1048    
1049    private static final class AnnotationRetrievingMethodVisitor extends MethodAdapter {
1050      private final MemberKey key;
1051      private final AnnotationReader reader;
1052
1053      private AnnotationRetrievingMethodVisitor(MethodVisitor mv, MemberKey key, AnnotationReader reader) {
1054        super(mv);
1055        this.key = key;
1056        this.reader = reader;
1057      }
1058
1059      public AnnotationVisitor visitAnnotation(final String JavaDoc desc, final boolean visible) {
1060          String JavaDoc className = toJavaName(desc);
1061          final AnnotationElement.Annotation annotation = new AnnotationElement.Annotation(className);
1062          if (reader.m_methodAnnotationElements.containsKey(key)) {
1063              ((Map JavaDoc) reader.m_methodAnnotationElements.get(key)).put(className, annotation);
1064          } else {
1065              final Map JavaDoc annotations = new HashMap JavaDoc();
1066              annotations.put(className, annotation);
1067              reader.m_methodAnnotationElements.put(key, annotations);
1068          }
1069          return reader.createAnnotationVisitor(annotation);
1070      }
1071    }
1072    
1073    private static final class AnnotationRetrievingFieldVisitor implements FieldVisitor {
1074      private final MemberKey key;
1075      private final FieldVisitor visitor;
1076      private final AnnotationReader reader;
1077
1078      private AnnotationRetrievingFieldVisitor(MemberKey key, FieldVisitor visitor, AnnotationReader reader) {
1079        this.key = key;
1080        this.visitor = visitor;
1081        this.reader = reader;
1082      }
1083
1084      public AnnotationVisitor visitAnnotation(final String JavaDoc desc, boolean visible) {
1085          final String JavaDoc className = toJavaName(desc);
1086          final AnnotationElement.Annotation annotation = new AnnotationElement.Annotation(className);
1087          if (reader.m_fieldAnnotationElements.containsKey(key)) {
1088              ((Map JavaDoc) reader.m_fieldAnnotationElements.get(key)).put(className, annotation);
1089          } else {
1090              final Map JavaDoc annotations = new HashMap JavaDoc();
1091              annotations.put(className, annotation);
1092              reader.m_fieldAnnotationElements.put(key, annotations);
1093          }
1094          return reader.createAnnotationVisitor(annotation);
1095      }
1096
1097      public void visitAttribute(final Attribute attribute) {
1098          visitor.visitAttribute(attribute);
1099      }
1100
1101      public void visitEnd() {
1102          visitor.visitEnd();
1103      }
1104    }
1105    
1106
1107    static class AnnotationBuilderVisitor implements AnnotationVisitor {
1108
1109        private final AnnotationElement.NestedAnnotationElement m_nestedAnnotationElement;
1110
1111        /**
1112         * ClassLoader from which both the annotated element and its annoation(s) are visible
1113         */

1114        private final ClassLoader JavaDoc m_loader;
1115
1116        /**
1117         * Annotation class name. If not null, default values will be handled, else it will be skip.
1118         * (f.e. skip for nested annotation and arrays)
1119         */

1120        private final String JavaDoc m_annotationClassName;
1121
1122        public AnnotationBuilderVisitor(final AnnotationElement.NestedAnnotationElement annotation,
1123                                        final ClassLoader JavaDoc loader,
1124                                        final String JavaDoc annotationClassName) {
1125            m_nestedAnnotationElement = annotation;
1126            m_loader = loader;
1127            m_annotationClassName = annotationClassName;
1128        }
1129
1130        public void visit(final String JavaDoc name, final Object JavaDoc value) {
1131            if (value instanceof Type) {
1132                // type
1133
m_nestedAnnotationElement.addElement(name, value);
1134            } else {
1135                // primitive value
1136
if (value.getClass().isArray()) {
1137                    // primitive array value
1138
handlePrimitiveArrayValue(value, name);
1139                } else {
1140                    // primitive non-array value
1141
m_nestedAnnotationElement.addElement(name, value);
1142                }
1143            }
1144        }
1145
1146        public void visitEnum(final String JavaDoc name, final String JavaDoc desc, final String JavaDoc value) {
1147            m_nestedAnnotationElement.addElement(name, new AnnotationElement.Enum(desc, value));
1148        }
1149
1150        public AnnotationVisitor visitAnnotation(final String JavaDoc name, final String JavaDoc desc) {
1151            String JavaDoc className = toJavaName(desc);
1152            AnnotationElement.NestedAnnotationElement annotation = new AnnotationElement.Annotation(className);
1153            m_nestedAnnotationElement.addElement(name, annotation);
1154            return new AnnotationBuilderVisitor(annotation, m_loader, className);//recursive default handling
1155
}
1156
1157        public AnnotationVisitor visitArray(final String JavaDoc name) {
1158            AnnotationElement.NestedAnnotationElement array = new AnnotationElement.Array();
1159            m_nestedAnnotationElement.addElement(name, array);
1160            return new AnnotationBuilderVisitor(array, m_loader, null);
1161        }
1162
1163        public void visitEnd() {
1164            // annotation default overrides
1165
if (m_annotationClassName != null) {
1166                AnnotationElement.Annotation defaults = AnnotationDefaults.getDefaults(m_annotationClassName, m_loader);
1167                AnnotationElement.Annotation annotation = (AnnotationElement.Annotation) m_nestedAnnotationElement;
1168                for (Iterator JavaDoc iterator = defaults.getElements().iterator(); iterator.hasNext();) {
1169                    AnnotationElement.NamedValue defaultedElement = (AnnotationElement.NamedValue) iterator.next();
1170                    annotation.mergeDefaultedElement(defaultedElement);
1171                }
1172            }
1173        }
1174
1175        /**
1176         * Handles array of primitive values. The JSR-175 spec. only suppots one dimensional arrays.
1177         *
1178         * @param value
1179         * @param name
1180         */

1181        private void handlePrimitiveArrayValue(final Object JavaDoc value, final String JavaDoc name) {
1182            if (value.getClass().getComponentType().isPrimitive()) {
1183                // primitive array type
1184
if (value instanceof String JavaDoc[]) {
1185                    // string array
1186
m_nestedAnnotationElement.addElement(name, value);
1187                } else {
1188                    AnnotationElement.NestedAnnotationElement arrayElement = new AnnotationElement.Array();
1189                    // non-string primitive array
1190
if (value instanceof int[]) {
1191                        int[] array = (int[]) value;
1192                        for (int i = 0; i < array.length; i++) {
1193                            arrayElement.addElement(null, new Integer JavaDoc(array[i]));
1194                        }
1195                    } else if (value instanceof long[]) {
1196                        long[] array = (long[]) value;
1197                        for (int i = 0; i < array.length; i++) {
1198                            arrayElement.addElement(null, new Long JavaDoc(array[i]));
1199                        }
1200                    } else if (value instanceof short[]) {
1201                        short[] array = (short[]) value;
1202                        for (int i = 0; i < array.length; i++) {
1203                            arrayElement.addElement(null, new Short JavaDoc(array[i]));
1204                        }
1205                    } else if (value instanceof float[]) {
1206                        float[] array = (float[]) value;
1207                        for (int i = 0; i < array.length; i++) {
1208                            arrayElement.addElement(null, new Float JavaDoc(array[i]));
1209                        }
1210                    } else if (value instanceof double[]) {
1211                        double[] array = (double[]) value;
1212                        for (int i = 0; i < array.length; i++) {
1213                            arrayElement.addElement(null, new Double JavaDoc(array[i]));
1214                        }
1215                    } else if (value instanceof boolean[]) {
1216                        boolean[] array = (boolean[]) value;
1217                        for (int i = 0; i < array.length; i++) {
1218                            arrayElement.addElement(null, new Boolean JavaDoc(array[i]));
1219                        }
1220                    } else if (value instanceof byte[]) {
1221                        byte[] array = (byte[]) value;
1222                        for (int i = 0; i < array.length; i++) {
1223                            arrayElement.addElement(null, new Byte JavaDoc(array[i]));
1224                        }
1225                    } else if (value instanceof char[]) {
1226                        char[] array = (char[]) value;
1227                        for (int i = 0; i < array.length; i++) {
1228                            arrayElement.addElement(null, new Character JavaDoc(array[i]));
1229                        }
1230                    }
1231                    m_nestedAnnotationElement.addElement(name, arrayElement);
1232                }
1233            } else {
1234                m_nestedAnnotationElement.addElement(name, value);
1235            }
1236        }
1237    }
1238
1239    /**
1240     * Contains info about the class being parsed. Holds the class name and a weak ref to the class loader. Also works
1241     * as a unique key. Needed since at bytecode parsing time we do not have access to the reflect members, only
1242     * strings.
1243     *
1244     * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér</a>
1245     */

1246    public static class ClassKey {
1247        private final String JavaDoc m_name;
1248        private final WeakReference JavaDoc m_loaderRef;
1249
1250        public ClassKey(final String JavaDoc name, final ClassLoader JavaDoc loader) {
1251            m_name = name.replace('.', '/');
1252            m_loaderRef = new WeakReference JavaDoc(loader);
1253        }
1254
1255        public String JavaDoc getName() {
1256            return m_name;
1257        }
1258
1259        public ClassLoader JavaDoc getClassLoader() {
1260            return (ClassLoader JavaDoc) m_loaderRef.get();
1261        }
1262
1263        public boolean equals(Object JavaDoc o) {
1264            if (this == o) {
1265                return true;
1266            }
1267            if (!(o instanceof ClassKey)) {
1268                return false;
1269            }
1270            final ClassKey classKey = (ClassKey) o;
1271            ClassLoader JavaDoc loader1 = (ClassLoader JavaDoc) m_loaderRef.get();
1272            ClassLoader JavaDoc loader2 = (ClassLoader JavaDoc) classKey.m_loaderRef.get();
1273            if (loader1 != null ? !loader1.equals(loader2) : loader2 != null) {
1274                return false;
1275            }
1276            if (m_name != null ? !m_name.equals(classKey.m_name) : classKey.m_name != null) {
1277                return false;
1278            }
1279            return true;
1280        }
1281
1282        public int hashCode() {
1283            int result;
1284            result = (m_name != null ? m_name.hashCode() : 0);
1285            ClassLoader JavaDoc loader = (ClassLoader JavaDoc) m_loaderRef.get();
1286            result = 29 * result + (loader != null ? loader.hashCode() : 0);
1287            return result;
1288        }
1289    }
1290
1291    /**
1292     * Unique key for class members (methods, fields and constructors) to be used in hash maps etc.
1293     * <p/>
1294     * Needed since at bytecode parsing time we do not have access to the reflect members, only strings.
1295     *
1296     * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér</a>
1297     */

1298    public static class MemberKey {
1299        private final String JavaDoc m_name;
1300        private final String JavaDoc m_desc;
1301
1302        public static MemberKey newConstructorKey(final Constructor JavaDoc method) {
1303            return new MemberKey(INIT_METHOD_NAME, SignatureHelper.getConstructorSignature(method));
1304        }
1305
1306        public static MemberKey newConstructorKey(final String JavaDoc desc) {
1307            return new MemberKey(INIT_METHOD_NAME, desc);
1308        }
1309
1310        public static MemberKey newMethodKey(final Method JavaDoc method) {
1311            return new MemberKey(method.getName(), SignatureHelper.getMethodSignature(method));
1312        }
1313
1314        public static MemberKey newMethodKey(final String JavaDoc name, final String JavaDoc desc) {
1315            return new MemberKey(name, desc);
1316        }
1317
1318        public static MemberKey newFieldKey(final Field JavaDoc field) {
1319            return new MemberKey(field.getName(), SignatureHelper.getFieldSignature(field));
1320        }
1321
1322        public static MemberKey newFieldKey(final String JavaDoc name, final String JavaDoc desc) {
1323            return new MemberKey(name, desc);
1324        }
1325
1326        public MemberKey(final String JavaDoc name, final String JavaDoc desc) {
1327            m_name = name;
1328            m_desc = desc;
1329        }
1330
1331        public boolean equals(Object JavaDoc o) {
1332            if (this == o) {
1333                return true;
1334            }
1335            if (!(o instanceof MemberKey)) {
1336                return false;
1337            }
1338            final MemberKey memberKey = (MemberKey) o;
1339            if (m_desc != null ? !m_desc.equals(memberKey.m_desc) : memberKey.m_desc != null) {
1340                return false;
1341            }
1342            if (m_name != null ? !m_name.equals(memberKey.m_name) : memberKey.m_name != null) {
1343                return false;
1344            }
1345            return true;
1346        }
1347
1348        public int hashCode() {
1349            int result;
1350            result = (m_name != null ? m_name.hashCode() : 0);
1351            result = 29 * result + (m_desc != null ? m_desc.hashCode() : 0);
1352            return result;
1353        }
1354    }
1355
1356    /**
1357     * To be used for debugging purposes.
1358     */

1359    private class TraceAnnotationVisitor implements AnnotationVisitor {
1360        public void visit(final String JavaDoc name, final Object JavaDoc value) {
1361            System.out.println(" NAMED-VALUE: " + name + "->" + value);
1362        }
1363
1364        public void visitEnum(final String JavaDoc name, final String JavaDoc desc, final String JavaDoc value) {
1365            System.out.println(" ENUM: " + name);
1366        }
1367
1368        public AnnotationVisitor visitAnnotation(final String JavaDoc name, final String JavaDoc desc) {
1369            System.out.println(" ANNOTATION: " + name);
1370            return new TraceAnnotationVisitor();
1371        }
1372
1373        public AnnotationVisitor visitArray(final String JavaDoc name) {
1374            System.out.println(" ARRAY: " + name);
1375            return new TraceAnnotationVisitor();
1376        }
1377
1378        public void visitEnd() {
1379        }
1380    }
1381}
1382
Popular Tags