0001: /*******************************************************************************************
0002: * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
0003: * http://backport175.codehaus.org *
0004: * --------------------------------------------------------------------------------------- *
0005: * The software in this package is published under the terms of Apache License Version 2.0 *
0006: * a copy of which has been included with this distribution in the license.txt file. *
0007: *******************************************************************************************/package com.tc.backport175.bytecode;
0008:
0009: import com.tc.backport175.Annotation;
0010: import com.tc.backport175.bytecode.spi.BytecodeProvider;
0011: import com.tc.backport175.proxy.ProxyFactory;
0012:
0013: import com.tc.asm.AnnotationVisitor;
0014: import com.tc.asm.ClassReader;
0015: import com.tc.asm.FieldVisitor;
0016: import com.tc.asm.MethodVisitor;
0017: import com.tc.asm.Type;
0018: import com.tc.asm.commons.EmptyVisitor;
0019:
0020: import java.lang.ref.Reference;
0021: import java.lang.ref.WeakReference;
0022: import java.lang.reflect.Constructor;
0023: import java.lang.reflect.Field;
0024: import java.lang.reflect.Method;
0025: import java.util.Collection;
0026: import java.util.HashMap;
0027: import java.util.Iterator;
0028: import java.util.Map;
0029: import java.util.WeakHashMap;
0030:
0031: /**
0032: * Reads Java 5 {@link java.lang.annotation.RetentionPolicy.RUNTIME} and
0033: * {@link java.lang.annotation.RetentionPolicy.CLASS} annotations from the class' bytecode.
0034: * <p/>
0035: * Can be used with a custom implementation of the {@link org.codehaus.backport175.reader.bytecode.spi.BytecodeProvider}
0036: * interface.
0037: * <p/>
0038: * Note: does not handles {@link java.lang.annotation.Inherited} feature. This has to be done in the higher level
0039: * that knows about the class hierarchy (see backport175.Annotations f.e)
0040: *
0041: * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér</a>
0042: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
0043: */
0044: public class AnnotationReader {
0045:
0046: private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
0047: private static final AnnotationElement.Annotation[] EMPTY_ANNOTATION_ELEMENT_ARRAY = new AnnotationElement.Annotation[0];
0048: private static final String INIT_METHOD_NAME = "<init>";
0049:
0050: private static final Map CLASS_SPECIFIC_BYTECODE_PROVIDER = new WeakHashMap();
0051: private static BytecodeProvider BYTECODE_PROVIDER = new DefaultBytecodeProvider();
0052:
0053: /**
0054: * Key is ClassKey, value is WeakReference of AnnotationReader
0055: */
0056: private static final Map READERS = new WeakHashMap();
0057:
0058: private final ClassKey m_classKey;
0059:
0060: // ===========================================================================
0061: // Implementation notes:
0062: // Parsing and annotation creation is made in two steps
0063: //
0064: // 1. The bytecode is parsed and the annotation content is put in elements,
0065: // which are stored for later processing
0066: //
0067: // 2. Upon annotation access the elements are processed and a dynamic proxy
0068: // for the annotation is created and cached.
0069: //
0070: // This gives much better performance than reflective access of Java 5
0071: // annotations (reflective access is around 5 times slower)
0072: // ===========================================================================
0073:
0074: private final Map m_classAnnotationElements = new HashMap();
0075: private final Map m_constructorAnnotationElements = new HashMap();
0076: private final Map m_methodAnnotationElements = new HashMap();
0077: private final Map m_fieldAnnotationElements = new HashMap();
0078:
0079: private final Map m_classAnnotationCache = new HashMap();
0080: private final Map m_constructorAnnotationCache = new HashMap();
0081: private final Map m_methodAnnotationCache = new HashMap();
0082: private final Map m_fieldAnnotationCache = new HashMap();
0083:
0084: /**
0085: * Sets the bytecode provider.
0086: * <p/>
0087: * If a custom provider is not set then a default impl will be used (which reads the bytecode from disk).
0088: *
0089: * @param bytecodeProvider
0090: */
0091: public static void setDefaultBytecodeProvider(
0092: final BytecodeProvider bytecodeProvider) {
0093: BYTECODE_PROVIDER = bytecodeProvider;
0094: }
0095:
0096: /**
0097: * Returns the bytecode provider.
0098: *
0099: * @return the bytecode provider
0100: */
0101: public static BytecodeProvider getDefaultBytecodeProvider() {
0102: return BYTECODE_PROVIDER;
0103: }
0104:
0105: /**
0106: * Sets the bytecode provider.
0107: * <p/>
0108: * If a custom provider is not set then a default impl will be used (which reads the bytecode from disk).
0109: *
0110: * @param klass
0111: * @param bytecodeProvider
0112: */
0113: public static void setBytecodeProviderFor(final Class klass,
0114: final BytecodeProvider bytecodeProvider) {
0115: setBytecodeProviderFor(klass.getName(), klass.getClassLoader(),
0116: bytecodeProvider);
0117: }
0118:
0119: /**
0120: * Sets the bytecode provider.
0121: * <p/>
0122: * If a custom provider is not set then a default impl will be used (which reads the bytecode from disk).
0123: *
0124: * @param className
0125: * @param loader
0126: * @param bytecodeProvider
0127: */
0128: public static void setBytecodeProviderFor(final String className,
0129: final ClassLoader loader,
0130: final BytecodeProvider bytecodeProvider) {
0131: CLASS_SPECIFIC_BYTECODE_PROVIDER.put(new ClassKey(className,
0132: loader), bytecodeProvider);
0133: }
0134:
0135: /**
0136: * Returns the bytecode provider.
0137: *
0138: * @param klass
0139: * @return the bytecode provider
0140: */
0141: public static BytecodeProvider getBytecodeProviderFor(
0142: final Class klass) {
0143: return getBytecodeProviderFor(klass.getName(), klass
0144: .getClassLoader());
0145: }
0146:
0147: /**
0148: * Returns the bytecode provider.
0149: *
0150: * @param className
0151: * @param loader
0152: * @return the bytecode provider
0153: */
0154: public static BytecodeProvider getBytecodeProviderFor(
0155: final String className, final ClassLoader loader) {
0156: BytecodeProvider bytecodeProvider = (BytecodeProvider) CLASS_SPECIFIC_BYTECODE_PROVIDER
0157: .get(new ClassKey(className, loader));
0158: if (bytecodeProvider == null) {
0159: return BYTECODE_PROVIDER;
0160: }
0161: return bytecodeProvider;
0162: }
0163:
0164: /**
0165: * Returns the bytecode for a class.
0166: *
0167: * @param className
0168: * @param loader
0169: * @return the bytecode for a class
0170: */
0171: public static byte[] getBytecodeFor(final String className,
0172: final ClassLoader loader) throws Exception {
0173: return getBytecodeProviderFor(className, loader).getBytecode(
0174: className, loader);
0175: }
0176:
0177: /**
0178: * Returns the annotation reader for the class specified.
0179: * <p/>
0180: * The annotation reader is created and cached if non-existant.
0181: *
0182: * @param klass
0183: * @return the annotation reader
0184: */
0185: public static AnnotationReader getReaderFor(final Class klass) {
0186: return getReaderFor(new ClassKey(klass.getName(), klass
0187: .getClassLoader()));
0188: }
0189:
0190: /**
0191: * Returns the annotation reader for the class specified.
0192: * <p/>
0193: * The annotation reader is created and cached if non-existant.
0194: *
0195: * @param className
0196: * @param loader
0197: * @return the annotation reader
0198: */
0199: public static AnnotationReader getReaderFor(final String className,
0200: final ClassLoader loader) {
0201: return getReaderFor(new ClassKey(className, loader));
0202: }
0203:
0204: /**
0205: * Returns the annotation reader for the class specified.
0206: * <p/>
0207: * The annotation reader is created and cached if non-existant.
0208: *
0209: * @param classKey
0210: * @return the annotation reader
0211: */
0212: public static AnnotationReader getReaderFor(final ClassKey classKey) {
0213: AnnotationReader reader;
0214: Object value = READERS.get(classKey);
0215: if (value == null) {
0216: synchronized (READERS) {
0217: reader = new AnnotationReader(classKey);
0218: READERS.put(classKey, new WeakReference(reader));//reader strong refs its own key in the weakhahsmap..
0219: }
0220: } else {
0221: reader = (AnnotationReader) ((Reference) value).get();
0222: if (reader == null) {//WeakReference content can be null
0223: synchronized (READERS) {
0224: reader = new AnnotationReader(classKey);
0225: READERS.put(classKey, new WeakReference(reader));
0226: }
0227: }
0228: }
0229: return reader;
0230: }
0231:
0232: /**
0233: * Resets the annotation reader for the class specified and triggers a new parsing of the newly read bytecode.
0234: * <p/>
0235: * This method calls <code>parse</code> and is therefore all the is needed to invoke to get a fully updated reader.
0236: *
0237: * @param klass
0238: */
0239: public static void refresh(final Class klass) {
0240: AnnotationReader reader = getReaderFor(klass);
0241: synchronized (reader) {
0242: reader.refresh();
0243: }
0244: }
0245:
0246: /**
0247: * Resets the annotation reader for the class specified and triggers a new parsing of the newly read bytecode.
0248: * <p/>
0249: * This method calls <code>parse</code> and is therefore all the is needed to invoke to get a fully updated reader.
0250: *
0251: * @param className
0252: * @param loader
0253: */
0254: public static void refresh(final String className,
0255: final ClassLoader loader) {
0256: AnnotationReader reader = getReaderFor(className, loader);
0257: synchronized (reader) {
0258: reader.refresh();
0259: }
0260: }
0261:
0262: /**
0263: * Resets *all* the annotation reader and triggers a new parsing of the newly read bytecode.
0264: * <p/>
0265: * This method will force parsing of all classes bytecode which might be very time consuming, use with care.
0266: * <p/>
0267: * This method calls <code>parse</code> and is therefore all the is needed to invoke to get a fully updated reader.
0268: */
0269: public static void refreshAll() {
0270: for (Iterator it = READERS.values().iterator(); it.hasNext();) {
0271: AnnotationReader reader = (AnnotationReader) ((Reference) it
0272: .next()).get();
0273: synchronized (reader) {
0274: reader.refresh();
0275: }
0276: }
0277: }
0278:
0279: /**
0280: * Converts the annotion class description to a Java class name.
0281: * Caution: Does not handles array type or primitive.
0282: *
0283: * @param desc
0284: * @return
0285: */
0286: public static String toJavaName(final String desc) {
0287: return desc.substring(1, desc.length() - 1).replace('/', '.');
0288: }
0289:
0290: /**
0291: * Checks if an annotation is present at a specific class.
0292: *
0293: * @param annotationName the annotation name
0294: * @return true if the annotation is present else false
0295: */
0296: public boolean isAnnotationPresent(final String annotationName) {
0297: return m_classAnnotationElements.containsKey(annotationName);
0298: }
0299:
0300: /**
0301: * Returns the class annotation with the name specified.
0302: *
0303: * @param annotationName
0304: * @return the class annotation
0305: */
0306: public Annotation getAnnotation(final String annotationName) {
0307: Object cachedAnnotation = m_classAnnotationCache
0308: .get(annotationName);
0309: if (cachedAnnotation != null) {
0310: return (Annotation) cachedAnnotation;
0311: } else {
0312: final Annotation annotation;
0313: final AnnotationElement.Annotation annotationInfo = (AnnotationElement.Annotation) m_classAnnotationElements
0314: .get(annotationName);
0315: if (annotationInfo != null) {
0316: annotation = ProxyFactory.newAnnotationProxy(
0317: annotationInfo, m_classKey.getClassLoader());
0318: m_classAnnotationCache.put(annotationName, annotation);
0319: return annotation;
0320: } else {
0321: return null;
0322: }
0323: }
0324: }
0325:
0326: /**
0327: * Returns all the class annotations.
0328: *
0329: * @return an array with the class annotations
0330: */
0331: public Annotation[] getAnnotations() {
0332: final Collection annotationNames = m_classAnnotationElements
0333: .keySet();
0334: if (annotationNames.isEmpty()) {
0335: return EMPTY_ANNOTATION_ARRAY;
0336: }
0337: final Annotation[] annotations = new Annotation[annotationNames
0338: .size()];
0339: int i = 0;
0340: for (Iterator iterator = annotationNames.iterator(); iterator
0341: .hasNext();) {
0342: String annotationName = (String) iterator.next();
0343: annotations[i++] = getAnnotation(annotationName);
0344: }
0345: return annotations;
0346: }
0347:
0348: /**
0349: * Checks if an annotation is present at a specific constructor.
0350: *
0351: * @param annotationName the annotation name
0352: * @param constructor the java.lang.reflect.Constructor object to find the annotations on.
0353: * @return true if the annotation is present else false
0354: */
0355: public boolean isAnnotationPresent(final String annotationName,
0356: final Constructor constructor) {
0357: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0358: .newConstructorKey(constructor);
0359: Object map = m_constructorAnnotationElements.get(key);
0360: if (map != null) {
0361: if (((Map) map).containsKey(annotationName)) {
0362: return true;
0363: }
0364: }
0365: return false;
0366: }
0367:
0368: /**
0369: * Returns the constructor annotation with the name specified for the constructor specified.
0370: *
0371: * @param annotationName the annotation name
0372: * @param constructor the java.lang.reflect.Constructor object to find the annotations on.
0373: * @return the constructor annotation
0374: */
0375: public Annotation getAnnotation(final String annotationName,
0376: final Constructor constructor) {
0377: return getConstructorAnnotation(annotationName, MemberKey
0378: .newConstructorKey(constructor), constructor
0379: .getDeclaringClass().getClassLoader());
0380: }
0381:
0382: /**
0383: * Returns the constructor annotation with the name specified for the constructor specified.
0384: *
0385: * @param annotationName
0386: * @param constructorDesc
0387: * @param loader
0388: * @return
0389: */
0390: public Annotation getConstructorAnnotation(
0391: final String annotationName, final String constructorDesc,
0392: final ClassLoader loader) {
0393: return getConstructorAnnotation(annotationName, MemberKey
0394: .newConstructorKey(constructorDesc), loader);
0395: }
0396:
0397: /**
0398: * Returns the constructor annotation with the name specified for the constructor specified.
0399: *
0400: * @param annotationName
0401: * @param constructorKey
0402: * @param loader
0403: * @return
0404: */
0405: private Annotation getConstructorAnnotation(
0406: final String annotationName,
0407: final MemberKey constructorKey, final ClassLoader loader) {
0408: Map annotationMap = getConstructorAnnotationCacheFor(constructorKey);
0409: Object cachedAnnotation = annotationMap.get(annotationName);
0410: if (cachedAnnotation != null) {
0411: return (Annotation) cachedAnnotation;
0412: }
0413: // not in cache - create a new DP and put in cache
0414: final Map annotations = (Map) m_constructorAnnotationElements
0415: .get(constructorKey);
0416: if (annotations == null) {
0417: // no such annotation
0418: return null;
0419: }
0420: Object annotationElement = annotations.get(annotationName);
0421: if (annotationElement != null) {
0422: Annotation annotation = ProxyFactory.newAnnotationProxy(
0423: (AnnotationElement.Annotation) annotationElement,
0424: loader);
0425: annotationMap.put(annotationName, annotation);
0426: return annotation;
0427: }
0428: return null;
0429: }
0430:
0431: /**
0432: * Returns all the constructor annotations.
0433: *
0434: * @param constructor the java.lang.reflect.Constructor object to find the annotations on.
0435: * @return an array with the constructor annotations
0436: */
0437: public Annotation[] getAnnotations(final Constructor constructor) {
0438: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0439: .newConstructorKey(constructor);
0440: Object map = m_constructorAnnotationElements.get(key);
0441: if (map != null) {
0442: final Collection annotationNames = ((Map) map).keySet();
0443: if (annotationNames.isEmpty()) {
0444: return EMPTY_ANNOTATION_ARRAY;
0445: }
0446: final Annotation[] annotations = new Annotation[annotationNames
0447: .size()];
0448: int i = 0;
0449: for (Iterator iterator = annotationNames.iterator(); iterator
0450: .hasNext();) {
0451: String annotationName = (String) iterator.next();
0452: annotations[i++] = getAnnotation(annotationName,
0453: constructor);
0454: }
0455: return annotations;
0456: } else {
0457: return EMPTY_ANNOTATION_ARRAY;
0458: }
0459: }
0460:
0461: /**
0462: * Checks if an annotation is present at a specific method.
0463: *
0464: * @param annotationName the annotation name
0465: * @param method the java.lang.reflect.Method object to find the annotations on.
0466: * @return true if the annotation is present else false
0467: */
0468: public boolean isAnnotationPresent(final String annotationName,
0469: final Method method) {
0470: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0471: .newMethodKey(method);
0472: Object map = m_methodAnnotationElements.get(key);
0473: if (map != null) {
0474: if (((Map) m_methodAnnotationElements.get(key))
0475: .containsKey(annotationName)) {
0476: return true;
0477: }
0478: }
0479: return false;
0480: }
0481:
0482: /**
0483: * Returns the method annotation with the name specified for the method specified.
0484: *
0485: * @param annotationName the annotation name
0486: * @param method the java.lang.reflect.Method object to find the annotations on.
0487: * @return the method annotation
0488: */
0489: public Annotation getAnnotation(final String annotationName,
0490: final Method method) {
0491: return getMethodAnnotation(annotationName, MemberKey
0492: .newMethodKey(method), method.getDeclaringClass()
0493: .getClassLoader());
0494: }
0495:
0496: /**
0497: * Returns the method annotation with the name specified for the method specified.
0498: *
0499: * @param annotationName
0500: * @param methodName
0501: * @param methodDesc
0502: * @param loader
0503: * @return
0504: */
0505: public Annotation getMethodAnnotation(final String annotationName,
0506: final String methodName, final String methodDesc,
0507: final ClassLoader loader) {
0508: return getMethodAnnotation(annotationName, MemberKey
0509: .newMethodKey(methodName, methodDesc), loader);
0510: }
0511:
0512: /**
0513: * Returns the method annotation with the name specified for the method specified.
0514: *
0515: * @param annotationName
0516: * @param methodKey
0517: * @param loader
0518: * @return
0519: */
0520: private Annotation getMethodAnnotation(final String annotationName,
0521: final MemberKey methodKey, final ClassLoader loader) {
0522: Map annotationMap = getMethodAnnotationCacheFor(methodKey);
0523: Object cachedAnnotation = annotationMap.get(annotationName);
0524: if (cachedAnnotation != null) {
0525: return (Annotation) cachedAnnotation;
0526: }
0527: // not in cache - create a new DP and put in cache
0528: final Map annotations = (Map) m_methodAnnotationElements
0529: .get(methodKey);
0530: if (annotations == null) {
0531: // no such annotation
0532: return null;
0533: }
0534: Object annotationElement = annotations.get(annotationName);
0535: if (annotationElement != null) {
0536: Annotation annotation = ProxyFactory.newAnnotationProxy(
0537: (AnnotationElement.Annotation) annotationElement,
0538: loader);
0539: annotationMap.put(annotationName, annotation);
0540: return annotation;
0541: }
0542: return null;
0543: }
0544:
0545: /**
0546: * Returns all the method annotations.
0547: *
0548: * @param method the java.lang.reflect.Method object to find the annotations on.
0549: * @return an array with the method annotations
0550: */
0551: public Annotation[] getAnnotations(final Method method) {
0552: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0553: .newMethodKey(method);
0554: Object map = m_methodAnnotationElements.get(key);
0555: if (map != null) {
0556: final Collection annotationNames = ((Map) map).keySet();
0557: if (annotationNames.isEmpty()) {
0558: return EMPTY_ANNOTATION_ARRAY;
0559: }
0560: final Annotation[] annotations = new Annotation[annotationNames
0561: .size()];
0562: int i = 0;
0563: for (Iterator iterator = annotationNames.iterator(); iterator
0564: .hasNext();) {
0565: String annotationName = (String) iterator.next();
0566: annotations[i++] = getAnnotation(annotationName, method);
0567: }
0568: return annotations;
0569: } else {
0570: return EMPTY_ANNOTATION_ARRAY;
0571: }
0572: }
0573:
0574: /**
0575: * Checks if an annotation is present at a specific field.
0576: *
0577: * @param annotationName the annotation name
0578: * @param field the java.lang.reflect.Field object to find the annotations on.
0579: * @return true if the annotation is present else false
0580: */
0581: public boolean isAnnotationPresent(final String annotationName,
0582: final Field field) {
0583: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0584: .newFieldKey(field);
0585: Object map = m_fieldAnnotationElements.get(key);
0586: if (map != null) {
0587: if (((Map) map).containsKey(annotationName)) {
0588: return true;
0589: }
0590: }
0591: return false;
0592: }
0593:
0594: /**
0595: * Returns the field annotation with the name specified for the field specified.
0596: *
0597: * @param annotationName the annotation name
0598: * @param field the java.lang.reflect.Field object to find the annotations on.
0599: * @return the field annotation
0600: */
0601: public Annotation getAnnotation(final String annotationName,
0602: final Field field) {
0603: return getFieldAnnotation(annotationName, MemberKey
0604: .newFieldKey(field), field.getDeclaringClass()
0605: .getClassLoader());
0606: }
0607:
0608: /**
0609: * Returns the field annotation with the name specified for the field specified.
0610: *
0611: * @param annotationName
0612: * @param fieldName
0613: * @param fieldDesc
0614: * @param loader
0615: * @return
0616: */
0617: public Annotation getFieldAnnotation(final String annotationName,
0618: final String fieldName, final String fieldDesc,
0619: final ClassLoader loader) {
0620: return getFieldAnnotation(annotationName, MemberKey
0621: .newFieldKey(fieldName, fieldDesc), loader);
0622: }
0623:
0624: /**
0625: * Returns the field annotation with the name specified for the field specified.
0626: *
0627: * @param annotationName
0628: * @param fieldKey
0629: * @param loader
0630: * @return
0631: */
0632: private Annotation getFieldAnnotation(final String annotationName,
0633: final MemberKey fieldKey, final ClassLoader loader) {
0634: Map annotationMap = getFieldAnnotationCacheFor(fieldKey);
0635: Object cachedAnnotation = annotationMap.get(annotationName);
0636: if (cachedAnnotation != null) {
0637: return (Annotation) cachedAnnotation;
0638: }
0639: // not in cache - create a new DP and put in cache
0640: final Map annotations = (Map) m_fieldAnnotationElements
0641: .get(fieldKey);
0642: if (annotations == null) {
0643: // no such annotation
0644: return null;
0645: }
0646: Object annotationElement = annotations.get(annotationName);
0647: if (annotationElement != null) {
0648: Annotation annotation = ProxyFactory.newAnnotationProxy(
0649: (AnnotationElement.Annotation) annotationElement,
0650: loader);
0651: annotationMap.put(annotationName, annotation);
0652: return annotation;
0653: }
0654: return null;
0655: }
0656:
0657: /**
0658: * Returns all the field annotations.
0659: *
0660: * @param field the java.lang.reflect.Field object to find the annotations on.
0661: * @return an array with the field annotations
0662: */
0663: public Annotation[] getAnnotations(final Field field) {
0664: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0665: .newFieldKey(field);
0666: Object map = m_fieldAnnotationElements.get(key);
0667: if (map != null) {
0668: final Collection annotationNames = ((Map) map).keySet();
0669: if (annotationNames.isEmpty()) {
0670: return EMPTY_ANNOTATION_ARRAY;
0671: }
0672: final Annotation[] annotations = new Annotation[annotationNames
0673: .size()];
0674: int i = 0;
0675: for (Iterator iterator = annotationNames.iterator(); iterator
0676: .hasNext();) {
0677: String annotationName = (String) iterator.next();
0678: annotations[i++] = getAnnotation(annotationName, field);
0679: }
0680: return annotations;
0681: } else {
0682: return EMPTY_ANNOTATION_ARRAY;
0683: }
0684: }
0685:
0686: /**
0687: * Returns the class annotation element with the name specified.
0688: *
0689: * @param annotationName
0690: * @return the class annotation
0691: */
0692: public AnnotationElement.Annotation getAnnotationElement(
0693: final String annotationName) {
0694: return (AnnotationElement.Annotation) m_classAnnotationElements
0695: .get(annotationName);
0696: }
0697:
0698: /**
0699: * Returns all the class annotations.
0700: *
0701: * @return an array with the class annotations
0702: */
0703: public AnnotationElement.Annotation[] getAnnotationElements() {
0704: final Collection annotations = m_classAnnotationElements
0705: .values();
0706: if (annotations.isEmpty()) {
0707: return EMPTY_ANNOTATION_ELEMENT_ARRAY;
0708: }
0709: return createAnnotationElementArray(annotations);
0710: }
0711:
0712: /**
0713: * Checks if an annotation is present at a specific constructor.
0714: *
0715: * @param annotationName the annotation name
0716: * @param desc the constructor desc
0717: * @return true if the annotation is present else false
0718: */
0719: public boolean isConstructorAnnotationPresent(
0720: final String annotationName, final String desc) {
0721: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0722: .newConstructorKey(desc);
0723: Object map = m_constructorAnnotationElements.get(key);
0724: if (map != null) {
0725: if (((Map) map).containsKey(annotationName)) {
0726: return true;
0727: }
0728: }
0729: return false;
0730: }
0731:
0732: /**
0733: * Returns the annotation with the name specified for the constructor specified.
0734: *
0735: * @param annotationName the annotation name
0736: * @param desc the constructor desc
0737: * @return the constructor annotation element
0738: */
0739: public AnnotationElement.Annotation getConstructorAnnotationElement(
0740: final String annotationName, final String desc) {
0741: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0742: .newConstructorKey(desc);
0743: final Map annotations = (Map) m_constructorAnnotationElements
0744: .get(key);
0745: if (annotations == null) {
0746: // no such annotation
0747: return null;
0748: }
0749: return (AnnotationElement.Annotation) annotations
0750: .get(annotationName);
0751: }
0752:
0753: /**
0754: * Returns all the constructor annotation elements.
0755: *
0756: * @param desc the constructor desc
0757: * @return an array with the constructor annotation elements
0758: */
0759: public AnnotationElement.Annotation[] getConstructorAnnotationElements(
0760: final String desc) {
0761: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0762: .newConstructorKey(desc);
0763: Object map = m_constructorAnnotationElements.get(key);
0764: if (map != null) {
0765: final Collection annotations = ((Map) map).values();
0766: if (annotations.isEmpty()) {
0767: return EMPTY_ANNOTATION_ELEMENT_ARRAY;
0768: }
0769: return createAnnotationElementArray(annotations);
0770: } else {
0771: return EMPTY_ANNOTATION_ELEMENT_ARRAY;
0772: }
0773: }
0774:
0775: /**
0776: * Checks if an annotation is present at a specific method.
0777: *
0778: * @param annotationName the annotation name
0779: * @param name the method name
0780: * @param desc the method desc
0781: * @return true if the annotation is present else false
0782: */
0783: public boolean isMethodAnnotationPresent(
0784: final String annotationName, final String name,
0785: final String desc) {
0786: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0787: .newMethodKey(name, desc);
0788: Object map = m_methodAnnotationElements.get(key);
0789: if (map != null) {
0790: if (((Map) map).containsKey(annotationName)) {
0791: return true;
0792: }
0793: }
0794: return false;
0795: }
0796:
0797: /**
0798: * Returns the method annotation with the name specified for the method specified.
0799: *
0800: * @param annotationName the annotation name
0801: * @param name the method name
0802: * @param desc the method desc
0803: * @return the method annotation element
0804: */
0805: public AnnotationElement.Annotation getMethodAnnotationElement(
0806: final String annotationName, final String name,
0807: final String desc) {
0808: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0809: .newMethodKey(name, desc);
0810: final Map annotations = (Map) m_methodAnnotationElements
0811: .get(key);
0812: if (annotations == null) {
0813: // no such annotation
0814: return null;
0815: }
0816: return (AnnotationElement.Annotation) annotations
0817: .get(annotationName);
0818: }
0819:
0820: /**
0821: * Returns all the method annotation elements.
0822: *
0823: * @param name the method name
0824: * @param desc the method desc
0825: * @return an array with the method annotation elements
0826: */
0827: public AnnotationElement.Annotation[] getMethodAnnotationElements(
0828: final String name, final String desc) {
0829: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0830: .newMethodKey(name, desc);
0831: Object map = m_methodAnnotationElements.get(key);
0832: if (map != null) {
0833: final Collection annotations = ((Map) m_methodAnnotationElements
0834: .get(key)).values();
0835: if (annotations.isEmpty()) {
0836: return EMPTY_ANNOTATION_ELEMENT_ARRAY;
0837: }
0838: return createAnnotationElementArray(annotations);
0839: } else {
0840: return EMPTY_ANNOTATION_ELEMENT_ARRAY;
0841: }
0842: }
0843:
0844: /**
0845: * Checks if an annotation is present at a specific field.
0846: *
0847: * @param annotationName the annotation name
0848: * @param name the field name
0849: * @param desc the field desc
0850: * @return true if the annotation is present else false
0851: */
0852: public boolean isFieldAnnotationPresent(
0853: final String annotationName, final String name,
0854: final String desc) {
0855: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0856: .newFieldKey(name, desc);
0857: Object map = m_fieldAnnotationElements.get(key);
0858: if (map != null) {
0859: if (((Map) map).containsKey(annotationName)) {
0860: return true;
0861: }
0862: }
0863: return false;
0864: }
0865:
0866: /**
0867: * Returns the annotation with the name specified for the field specified.
0868: *
0869: * @param annotationName the annotation name
0870: * @param name the field name
0871: * @param desc the field desc
0872: * @return the field annotation element
0873: */
0874: public AnnotationElement.Annotation getFieldAnnotationElement(
0875: final String annotationName, final String name,
0876: final String desc) {
0877: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0878: .newFieldKey(name, desc);
0879: final Map annotations = (Map) m_fieldAnnotationElements
0880: .get(key);
0881: if (annotations == null) {
0882: // no such annotation
0883: return null;
0884: }
0885: return (AnnotationElement.Annotation) annotations
0886: .get(annotationName);
0887: }
0888:
0889: /**
0890: * Returns all the field annotation elements.
0891: *
0892: * @param name the field name
0893: * @param desc the field desc
0894: * @return an array with the field annotation elements
0895: */
0896: public AnnotationElement.Annotation[] getFieldAnnotationElements(
0897: final String name, final String desc) {
0898: final AnnotationReader.MemberKey key = AnnotationReader.MemberKey
0899: .newFieldKey(name, desc);
0900: Object map = m_fieldAnnotationElements.get(key);
0901: if (map != null) {
0902: final Collection annotations = ((Map) m_fieldAnnotationElements
0903: .get(key)).values();
0904: if (annotations.isEmpty()) {
0905: return EMPTY_ANNOTATION_ELEMENT_ARRAY;
0906: }
0907: return createAnnotationElementArray(annotations);
0908: } else {
0909: return EMPTY_ANNOTATION_ELEMENT_ARRAY;
0910: }
0911: }
0912:
0913: /**
0914: * Creates an annotation element array.
0915: *
0916: * @param annotations the collection with elements
0917: * @return the array
0918: */
0919: private AnnotationElement.Annotation[] createAnnotationElementArray(
0920: final Collection annotations) {
0921: int i = 0;
0922: final AnnotationElement.Annotation[] elementArray = new AnnotationElement.Annotation[annotations
0923: .size()];
0924: for (Iterator it = annotations.iterator(); it.hasNext();) {
0925: elementArray[i++] = (AnnotationElement.Annotation) it
0926: .next();
0927: }
0928: return elementArray;
0929: }
0930:
0931: /**
0932: * Returns the annotation cache for a specific constructor.
0933: *
0934: * @param constructor the constructor
0935: * @return the cache
0936: */
0937: private Map getConstructorAnnotationCacheFor(
0938: final MemberKey constructor) {
0939: Map annotationMap = (Map) m_constructorAnnotationCache
0940: .get(constructor);
0941: if (annotationMap == null) {
0942: annotationMap = new HashMap();
0943: m_constructorAnnotationCache
0944: .put(constructor, annotationMap);
0945: }
0946: return annotationMap;
0947: }
0948:
0949: /**
0950: * Returns the annotation cache for a specific method.
0951: *
0952: * @param method the method
0953: * @return the cache
0954: */
0955: private Map getMethodAnnotationCacheFor(final MemberKey method) {
0956: Map annotationMap = (Map) m_methodAnnotationCache.get(method);
0957: if (annotationMap == null) {
0958: annotationMap = new HashMap();
0959: m_methodAnnotationCache.put(method, annotationMap);
0960: }
0961: return annotationMap;
0962: }
0963:
0964: /**
0965: * Returns the annotation cache for a specific field.
0966: *
0967: * @param field the field
0968: * @return the cache
0969: */
0970: private Map getFieldAnnotationCacheFor(final MemberKey field) {
0971: Map annotationMap = (Map) m_fieldAnnotationCache.get(field);
0972: if (annotationMap == null) {
0973: annotationMap = new HashMap();
0974: m_fieldAnnotationCache.put(field, annotationMap);
0975: }
0976: return annotationMap;
0977: }
0978:
0979: /**
0980: * Resets the annotation reader and triggers a new parsing of the newly read bytecode.
0981: * <p/>
0982: * This method calls <code>parse</code> and is therefore all the is needed to invoke to get a fully updated reader.
0983: */
0984: private void refresh() {
0985: m_classAnnotationElements.clear();
0986: m_constructorAnnotationElements.clear();
0987: m_methodAnnotationElements.clear();
0988: m_fieldAnnotationElements.clear();
0989: m_classAnnotationCache.clear();
0990: m_constructorAnnotationCache.clear();
0991: m_methodAnnotationCache.clear();
0992: m_fieldAnnotationCache.clear();
0993: AnnotationDefaults.refresh(m_classKey);
0994: parse(m_classKey);
0995: }
0996:
0997: /**
0998: * Parses the class bytecode and retrieves the annotations.
0999: *
1000: * @param classKey
1001: */
1002: private void parse(final ClassKey classKey) {
1003: final String className = classKey.getName();
1004: final ClassLoader loader = classKey.getClassLoader();
1005: final byte[] bytes;
1006: try {
1007: bytes = getBytecodeFor(className, loader);
1008: } catch (Exception e) {
1009: // e.printStackTrace();
1010: System.err.println("[WARN] " + e.getMessage());
1011: return;
1012: // throw new ReaderException(
1013: // "could not retrieve the bytecode for class [" + className + "]", e
1014: // );
1015: }
1016: ClassReader classReader = new ClassReader(bytes);
1017: classReader.accept(new AnnotationRetrievingVisitor(),
1018: ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE
1019: | ClassReader.SKIP_FRAMES);
1020: }
1021:
1022: /**
1023: * Creates a new instance of the annotation reader, reads from the class specified.
1024: *
1025: * @param classKey
1026: */
1027: private AnnotationReader(final ClassKey classKey) {
1028: if (classKey == null) {
1029: throw new IllegalArgumentException(
1030: "class info can not be null");
1031: }
1032: m_classKey = classKey;
1033: parse(classKey);
1034: }
1035:
1036: /**
1037: * Retrieves the Java 5 RuntimeVisibleAnnotations annotations from the class bytecode.
1038: */
1039: class AnnotationRetrievingVisitor extends EmptyVisitor {
1040:
1041: public AnnotationVisitor visitAnnotation(final String desc,
1042: final boolean visible) {
1043: String annotationClassName = toJavaName(desc);
1044: final AnnotationElement.Annotation annotation = new AnnotationElement.Annotation(
1045: annotationClassName);
1046: m_classAnnotationElements.put(annotationClassName,
1047: annotation);
1048: return createAnnotationVisitor(annotation);
1049: }
1050:
1051: public FieldVisitor visitField(final int access,
1052: final String name, final String desc,
1053: final String signature, final Object value) {
1054: final MemberKey key = new MemberKey(name, desc);
1055: return new AnnotationRetrievingFieldVisitor(key,
1056: AnnotationReader.this );
1057: }
1058:
1059: public MethodVisitor visitMethod(final int access,
1060: final String name, final String desc,
1061: final String signature, final String[] exceptions) {
1062: final MemberKey key = new MemberKey(name, desc);
1063: if (name.equals(INIT_METHOD_NAME)) {
1064: return new AnnotationRetrievingConstructorVisitor(key,
1065: AnnotationReader.this );
1066: } else {
1067: return new AnnotationRetrievingMethodVisitor(key,
1068: AnnotationReader.this );
1069: }
1070: }
1071:
1072: }
1073:
1074: /**
1075: * Returns the annotation visitor to use.
1076: * <p/>
1077: * Swap to the 'tracing' visitor for simple debugging.
1078: *
1079: * @param annotation
1080: * @return
1081: */
1082: public AnnotationVisitor createAnnotationVisitor(
1083: final AnnotationElement.Annotation annotation) {
1084: return new AnnotationBuilderVisitor(annotation, m_classKey
1085: .getClassLoader(), annotation.getInterfaceName());
1086: // return new TraceAnnotationVisitor();
1087: }
1088:
1089: static final class AnnotationRetrievingConstructorVisitor extends
1090: EmptyVisitor {
1091: private final MemberKey key;
1092: private final AnnotationReader reader;
1093:
1094: AnnotationRetrievingConstructorVisitor(MemberKey key,
1095: AnnotationReader reader) {
1096: this .key = key;
1097: this .reader = reader;
1098: }
1099:
1100: public AnnotationVisitor visitAnnotation(final String desc,
1101: final boolean visible) {
1102: final String className = toJavaName(desc);
1103: final AnnotationElement.Annotation annotation = new AnnotationElement.Annotation(
1104: className);
1105: if (reader.m_constructorAnnotationElements.containsKey(key)) {
1106: ((Map) reader.m_constructorAnnotationElements.get(key))
1107: .put(className, annotation);
1108: } else {
1109: final Map annotations = new HashMap();
1110: annotations.put(className, annotation);
1111: reader.m_constructorAnnotationElements.put(key,
1112: annotations);
1113: }
1114: return reader.createAnnotationVisitor(annotation);
1115: }
1116: }
1117:
1118: static final class AnnotationRetrievingMethodVisitor extends
1119: EmptyVisitor {
1120: private final MemberKey key;
1121: private final AnnotationReader reader;
1122:
1123: AnnotationRetrievingMethodVisitor(MemberKey key,
1124: AnnotationReader reader) {
1125: this .key = key;
1126: this .reader = reader;
1127: }
1128:
1129: public AnnotationVisitor visitAnnotation(final String desc,
1130: final boolean visible) {
1131: String className = toJavaName(desc);
1132: final AnnotationElement.Annotation annotation = new AnnotationElement.Annotation(
1133: className);
1134: if (reader.m_methodAnnotationElements.containsKey(key)) {
1135: ((Map) reader.m_methodAnnotationElements.get(key)).put(
1136: className, annotation);
1137: } else {
1138: final Map annotations = new HashMap();
1139: annotations.put(className, annotation);
1140: reader.m_methodAnnotationElements.put(key, annotations);
1141: }
1142: return reader.createAnnotationVisitor(annotation);
1143: }
1144: }
1145:
1146: static final class AnnotationRetrievingFieldVisitor extends
1147: EmptyVisitor {
1148: private final MemberKey key;
1149: private final AnnotationReader reader;
1150:
1151: AnnotationRetrievingFieldVisitor(MemberKey key,
1152: AnnotationReader reader) {
1153: this .key = key;
1154: this .reader = reader;
1155: }
1156:
1157: public AnnotationVisitor visitAnnotation(final String desc,
1158: boolean visible) {
1159: final String className = toJavaName(desc);
1160: final AnnotationElement.Annotation annotation = new AnnotationElement.Annotation(
1161: className);
1162: if (reader.m_fieldAnnotationElements.containsKey(key)) {
1163: ((Map) reader.m_fieldAnnotationElements.get(key)).put(
1164: className, annotation);
1165: } else {
1166: final Map annotations = new HashMap();
1167: annotations.put(className, annotation);
1168: reader.m_fieldAnnotationElements.put(key, annotations);
1169: }
1170: return reader.createAnnotationVisitor(annotation);
1171: }
1172:
1173: }
1174:
1175: static class AnnotationBuilderVisitor implements AnnotationVisitor {
1176:
1177: private final AnnotationElement.NestedAnnotationElement m_nestedAnnotationElement;
1178:
1179: /**
1180: * ClassLoader from which both the annotated element and its annoation(s) are visible
1181: */
1182: private final ClassLoader m_loader;
1183:
1184: /**
1185: * Annotation class name. If not null, default values will be handled, else it will be skip.
1186: * (f.e. skip for nested annotation and arrays)
1187: */
1188: private final String m_annotationClassName;
1189:
1190: public AnnotationBuilderVisitor(
1191: final AnnotationElement.NestedAnnotationElement annotation,
1192: final ClassLoader loader,
1193: final String annotationClassName) {
1194: m_nestedAnnotationElement = annotation;
1195: m_loader = loader;
1196: m_annotationClassName = annotationClassName;
1197: }
1198:
1199: public void visit(final String name, final Object value) {
1200: if (value instanceof Type) {
1201: // type
1202: m_nestedAnnotationElement.addElement(name, value);
1203: } else {
1204: // primitive value
1205: if (value.getClass().isArray()) {
1206: // primitive array value
1207: handlePrimitiveArrayValue(value, name);
1208: } else {
1209: // primitive non-array value
1210: m_nestedAnnotationElement.addElement(name, value);
1211: }
1212: }
1213: }
1214:
1215: public void visitEnum(final String name, final String desc,
1216: final String value) {
1217: m_nestedAnnotationElement.addElement(name,
1218: new AnnotationElement.Enum(desc, value));
1219: }
1220:
1221: public AnnotationVisitor visitAnnotation(final String name,
1222: final String desc) {
1223: String className = toJavaName(desc);
1224: AnnotationElement.NestedAnnotationElement annotation = new AnnotationElement.Annotation(
1225: className);
1226: m_nestedAnnotationElement.addElement(name, annotation);
1227: return new AnnotationBuilderVisitor(annotation, m_loader,
1228: className);//recursive default handling
1229: }
1230:
1231: public AnnotationVisitor visitArray(final String name) {
1232: AnnotationElement.NestedAnnotationElement array = new AnnotationElement.Array();
1233: m_nestedAnnotationElement.addElement(name, array);
1234: return new AnnotationBuilderVisitor(array, m_loader, null);
1235: }
1236:
1237: public void visitEnd() {
1238: // annotation default overrides
1239: if (m_annotationClassName != null) {
1240: AnnotationElement.Annotation defaults = AnnotationDefaults
1241: .getDefaults(m_annotationClassName, m_loader);
1242: AnnotationElement.Annotation annotation = (AnnotationElement.Annotation) m_nestedAnnotationElement;
1243: for (Iterator iterator = defaults.getElements()
1244: .iterator(); iterator.hasNext();) {
1245: AnnotationElement.NamedValue defaultedElement = (AnnotationElement.NamedValue) iterator
1246: .next();
1247: annotation.mergeDefaultedElement(defaultedElement);
1248: }
1249: }
1250: }
1251:
1252: /**
1253: * Handles array of primitive values. The JSR-175 spec. only suppots one dimensional arrays.
1254: *
1255: * @param value
1256: * @param name
1257: */
1258: private void handlePrimitiveArrayValue(final Object value,
1259: final String name) {
1260: if (value.getClass().getComponentType().isPrimitive()) {
1261: // primitive array type
1262: if (value instanceof String[]) {
1263: // string array
1264: m_nestedAnnotationElement.addElement(name, value);
1265: } else {
1266: AnnotationElement.NestedAnnotationElement arrayElement = new AnnotationElement.Array();
1267: // non-string primitive array
1268: if (value instanceof int[]) {
1269: int[] array = (int[]) value;
1270: for (int i = 0; i < array.length; i++) {
1271: arrayElement.addElement(null, new Integer(
1272: array[i]));
1273: }
1274: } else if (value instanceof long[]) {
1275: long[] array = (long[]) value;
1276: for (int i = 0; i < array.length; i++) {
1277: arrayElement.addElement(null, new Long(
1278: array[i]));
1279: }
1280: } else if (value instanceof short[]) {
1281: short[] array = (short[]) value;
1282: for (int i = 0; i < array.length; i++) {
1283: arrayElement.addElement(null, new Short(
1284: array[i]));
1285: }
1286: } else if (value instanceof float[]) {
1287: float[] array = (float[]) value;
1288: for (int i = 0; i < array.length; i++) {
1289: arrayElement.addElement(null, new Float(
1290: array[i]));
1291: }
1292: } else if (value instanceof double[]) {
1293: double[] array = (double[]) value;
1294: for (int i = 0; i < array.length; i++) {
1295: arrayElement.addElement(null, new Double(
1296: array[i]));
1297: }
1298: } else if (value instanceof boolean[]) {
1299: boolean[] array = (boolean[]) value;
1300: for (int i = 0; i < array.length; i++) {
1301: arrayElement.addElement(null, new Boolean(
1302: array[i]));
1303: }
1304: } else if (value instanceof byte[]) {
1305: byte[] array = (byte[]) value;
1306: for (int i = 0; i < array.length; i++) {
1307: arrayElement.addElement(null, new Byte(
1308: array[i]));
1309: }
1310: } else if (value instanceof char[]) {
1311: char[] array = (char[]) value;
1312: for (int i = 0; i < array.length; i++) {
1313: arrayElement.addElement(null,
1314: new Character(array[i]));
1315: }
1316: }
1317: m_nestedAnnotationElement.addElement(name,
1318: arrayElement);
1319: }
1320: } else {
1321: m_nestedAnnotationElement.addElement(name, value);
1322: }
1323: }
1324: }
1325:
1326: /**
1327: * Contains info about the class being parsed. Holds the class name and a weak ref to the class loader. Also works
1328: * as a unique key. Needed since at bytecode parsing time we do not have access to the reflect members, only
1329: * strings.
1330: *
1331: * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér</a>
1332: */
1333: public static class ClassKey {
1334: private final String m_name;
1335: private final WeakReference m_loaderRef;
1336:
1337: public ClassKey(final String name, final ClassLoader loader) {
1338: m_name = name.replace('.', '/');
1339: m_loaderRef = new WeakReference(loader);
1340: }
1341:
1342: public String getName() {
1343: return m_name;
1344: }
1345:
1346: public ClassLoader getClassLoader() {
1347: return (ClassLoader) m_loaderRef.get();
1348: }
1349:
1350: public boolean equals(Object o) {
1351: if (this == o) {
1352: return true;
1353: }
1354: if (!(o instanceof ClassKey)) {
1355: return false;
1356: }
1357: final ClassKey classKey = (ClassKey) o;
1358: ClassLoader loader1 = (ClassLoader) m_loaderRef.get();
1359: ClassLoader loader2 = (ClassLoader) classKey.m_loaderRef
1360: .get();
1361: if (loader1 != null ? !loader1.equals(loader2)
1362: : loader2 != null) {
1363: return false;
1364: }
1365: if (m_name != null ? !m_name.equals(classKey.m_name)
1366: : classKey.m_name != null) {
1367: return false;
1368: }
1369: return true;
1370: }
1371:
1372: public int hashCode() {
1373: int result;
1374: result = (m_name != null ? m_name.hashCode() : 0);
1375: ClassLoader loader = (ClassLoader) m_loaderRef.get();
1376: result = 29 * result
1377: + (loader != null ? loader.hashCode() : 0);
1378: return result;
1379: }
1380: }
1381:
1382: /**
1383: * Unique key for class members (methods, fields and constructors) to be used in hash maps etc.
1384: * <p/>
1385: * Needed since at bytecode parsing time we do not have access to the reflect members, only strings.
1386: *
1387: * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér</a>
1388: */
1389: public static class MemberKey {
1390: private final String m_name;
1391: private final String m_desc;
1392:
1393: public static MemberKey newConstructorKey(
1394: final Constructor method) {
1395: return new MemberKey(INIT_METHOD_NAME, SignatureHelper
1396: .getConstructorSignature(method));
1397: }
1398:
1399: public static MemberKey newConstructorKey(final String desc) {
1400: return new MemberKey(INIT_METHOD_NAME, desc);
1401: }
1402:
1403: public static MemberKey newMethodKey(final Method method) {
1404: return new MemberKey(method.getName(), SignatureHelper
1405: .getMethodSignature(method));
1406: }
1407:
1408: public static MemberKey newMethodKey(final String name,
1409: final String desc) {
1410: return new MemberKey(name, desc);
1411: }
1412:
1413: public static MemberKey newFieldKey(final Field field) {
1414: return new MemberKey(field.getName(), SignatureHelper
1415: .getFieldSignature(field));
1416: }
1417:
1418: public static MemberKey newFieldKey(final String name,
1419: final String desc) {
1420: return new MemberKey(name, desc);
1421: }
1422:
1423: public MemberKey(final String name, final String desc) {
1424: m_name = name;
1425: m_desc = desc;
1426: }
1427:
1428: public boolean equals(Object o) {
1429: if (this == o) {
1430: return true;
1431: }
1432: if (!(o instanceof MemberKey)) {
1433: return false;
1434: }
1435: final MemberKey memberKey = (MemberKey) o;
1436: if (m_desc != null ? !m_desc.equals(memberKey.m_desc)
1437: : memberKey.m_desc != null) {
1438: return false;
1439: }
1440: if (m_name != null ? !m_name.equals(memberKey.m_name)
1441: : memberKey.m_name != null) {
1442: return false;
1443: }
1444: return true;
1445: }
1446:
1447: public int hashCode() {
1448: int result;
1449: result = (m_name != null ? m_name.hashCode() : 0);
1450: result = 29 * result
1451: + (m_desc != null ? m_desc.hashCode() : 0);
1452: return result;
1453: }
1454: }
1455:
1456: /**
1457: * To be used for debugging purposes.
1458: */
1459: private class TraceAnnotationVisitor implements AnnotationVisitor {
1460: public void visit(final String name, final Object value) {
1461: System.out.println(" NAMED-VALUE: " + name + "->"
1462: + value);
1463: }
1464:
1465: public void visitEnum(final String name, final String desc,
1466: final String value) {
1467: System.out.println(" ENUM: " + name);
1468: }
1469:
1470: public AnnotationVisitor visitAnnotation(final String name,
1471: final String desc) {
1472: System.out.println(" ANNOTATION: " + name);
1473: return new TraceAnnotationVisitor();
1474: }
1475:
1476: public AnnotationVisitor visitArray(final String name) {
1477: System.out.println(" ARRAY: " + name);
1478: return new TraceAnnotationVisitor();
1479: }
1480:
1481: public void visitEnd() {
1482: }
1483: }
1484: }
|