View Javadoc

    1   /***************************************************************************************
    2    * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved.                 *
    3    * http://aspectwerkz.codehaus.org                                                    *
    4    * ---------------------------------------------------------------------------------- *
    5    * The software in this package is published under the terms of the LGPL license      *
    6    * a copy of which has been included with this distribution in the license.txt file.  *
    7    **************************************************************************************/
    8   package org.codehaus.aspectwerkz.reflect.impl.java;
    9
    10  import gnu.trove.TIntObjectHashMap;
    11  import org.codehaus.aspectwerkz.annotation.Annotations;
    12  import org.codehaus.aspectwerkz.reflect.ClassInfo;
    13  import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
    14  import org.codehaus.aspectwerkz.reflect.FieldInfo;
    15  import org.codehaus.aspectwerkz.reflect.MethodInfo;
    16  import org.codehaus.aspectwerkz.reflect.ReflectHelper;
    17  import org.codehaus.aspectwerkz.reflect.ReflectHelper;
    18  import org.codehaus.aspectwerkz.reflect.StaticInitializationInfo;
    19  import org.codehaus.aspectwerkz.reflect.StaticInitializationInfoImpl;
    20  import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
    21  import org.codehaus.aspectwerkz.transform.TransformationConstants;
    22
    23  import java.lang.reflect.Constructor;
    24  import java.lang.reflect.Field;
    25  import java.lang.reflect.Method;
    26  import java.util.List;
    27
    28  /***
    29   * Implementation of the ClassInfo interface for java.lang.reflect.*.
    30   *
    31   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    32   */
    33  public class JavaClassInfo implements ClassInfo {
    34      /***
    35       * The class.
    36       */
    37      // TODO might be safer to wrap this member in a weak ref
    38      private final Class m_class;
    39
    40      /***
    41       * The name of the class.
    42       */
    43      private String m_name;
    44
    45      /***
    46       * The signature of the class.
    47       */
    48      private String m_signature;
    49
    50      /***
    51       * Is the class an interface.
    52       */
    53      private boolean m_isInterface = false;
    54
    55      /***
    56       * Is the class a primitive type.
    57       */
    58      private boolean m_isPrimitive = false;
    59
    60      /***
    61       * Is the class of type array.
    62       */
    63      private boolean m_isArray = false;
    64
    65      /***
    66       * A list with the <code>ConstructorInfo</code> instances.
    67       */
    68      private final TIntObjectHashMap m_constructors = new TIntObjectHashMap();
    69
    70      /***
    71       * A list with the <code>MethodInfo</code> instances.
    72       */
    73      private final TIntObjectHashMap m_methods = new TIntObjectHashMap();
    74
    75      /***
    76       * A list with the <code>FieldInfo</code> instances.
    77       */
    78      private final TIntObjectHashMap m_fields = new TIntObjectHashMap();
    79
    80      /***
    81       * A list with the interfaces.
    82       */
    83      private ClassInfo[] m_interfaces = null;
    84
    85      /***
    86       * The super class.
    87       */
    88      private ClassInfo m_superClass = null;
    89
    90      /***
    91       * The annotations.
    92       */
    93      private List m_annotations = null;
    94
    95      /***
    96       * The component type if array type.
    97       */
    98      private ClassInfo m_componentType = null;
    99
    100     /***
    101      * The class info repository.
    102      */
    103     private final JavaClassInfoRepository m_classInfoRepository;
    104
    105     /***
    106      * Lazy, the static initializer info or null if not present
    107      */
    108     private StaticInitializationInfo m_staticInitializer = null;
    109
    110     /***
    111      * Creates a new class meta data instance.
    112      *
    113      * @param klass
    114      */
    115     JavaClassInfo(final Class klass) {
    116         if (klass == null) {
    117             throw new IllegalArgumentException("class can not be null");
    118         }
    119         m_class = klass;
    120
    121         m_signature = ReflectHelper.getClassSignature(klass);
    122
    123         m_classInfoRepository = JavaClassInfoRepository.getRepository(klass.getClassLoader());
    124         m_isInterface = klass.isInterface();
    125         if (klass.isPrimitive()) {
    126             m_name = klass.getName();
    127             m_isPrimitive = true;
    128         } else if (klass.getComponentType() != null) {
    129             m_name = convertJavaArrayTypeNameToHumanTypeName(klass.getName());
    130             m_isArray = true;
    131             m_interfaces = new ClassInfo[0];
    132         } else {
    133             m_name = klass.getName();
    134             Method[] methods = m_class.getDeclaredMethods();
    135             for (int i = 0; i < methods.length; i++) {
    136                 Method method = methods[i];
    137                 m_methods.put(ReflectHelper.calculateHash(method), new JavaMethodInfo(method, this));
    138             }
    139             Constructor[] constructors = m_class.getDeclaredConstructors();
    140             for (int i = 0; i < constructors.length; i++) {
    141                 Constructor constructor = constructors[i];
    142                 m_constructors.put(
    143                         ReflectHelper.calculateHash(constructor), new JavaConstructorInfo(
    144                                 constructor,
    145                                 this
    146                         )
    147                 );
    148             }
    149             Field[] fields = m_class.getDeclaredFields();
    150             for (int i = 0; i < fields.length; i++) {
    151                 if (fields[i].getName().startsWith(TransformationConstants.ASPECTWERKZ_PREFIX)) {
    152                     continue;
    153                 }
    154                 Field field = fields[i];
    155                 m_fields.put(ReflectHelper.calculateHash(field), new JavaFieldInfo(field, this));
    156             }
    157         }
    158         m_classInfoRepository.addClassInfo(this);
    159     }
    160
    161     /***
    162      * Returns the class info for a specific class.
    163      *
    164      * @return the class info
    165      */
    166     public static ClassInfo getClassInfo(final Class clazz) {
    167         JavaClassInfoRepository repository = JavaClassInfoRepository.getRepository(clazz.getClassLoader());
    168         ClassInfo classInfo = repository.getClassInfo(clazz.getName());
    169         if (classInfo == null) {
    170             classInfo = new JavaClassInfo(clazz);
    171         }
    172         return classInfo;
    173     }
    174
    175     /***
    176      * Returns the annotations infos.
    177      *
    178      * @return the annotations infos
    179      */
    180     public List getAnnotations() {
    181         if (m_annotations == null) {
    182             // TODO this means that JavaClassInfo is always using AsmClassInfo to get that annotations
    183             // TODO should optimize for Java5
    184             m_annotations = Annotations.getAnnotationInfos(m_class);
    185         }
    186         return m_annotations;
    187     }
    188
    189     /***
    190      * Returns the name of the class.
    191      *
    192      * @return the name of the class
    193      */
    194     public String getName() {
    195         return m_name.replace('/', '.');
    196     }
    197
    198     /***
    199      * Checks if the class has a static initalizer.
    200      *
    201      * @return
    202      */
    203     public boolean hasStaticInitializer() {
    204         ClassInfo classInfo = AsmClassInfo.getClassInfo(getName(), getClassLoader());
    205         return classInfo.hasStaticInitializer();
    206     }
    207
    208 	/***
    209 	 * Returns the static initializer info of the current underlying class if any.
    210 	 *
    211 	 * @see org.codehaus.aspectwerkz.reflect.ClassInfo#staticInitializer()
    212 	 */
    213 	public StaticInitializationInfo staticInitializer() {
    214 		if(hasStaticInitializer() && m_staticInitializer == null) {
    215 			m_staticInitializer = new StaticInitializationInfoImpl(this);
    216 		}
    217 		return m_staticInitializer;
    218 	}
    219
    220     /***
    221      * Returns the signature for the element.
    222      *
    223      * @return the signature for the element
    224      */
    225     public String getSignature() {
    226         return m_signature;
    227     }
    228
    229     /***
    230      * Returns the class modifiers.
    231      *
    232      * @return the class modifiers
    233      */
    234     public int getModifiers() {
    235         return m_class.getModifiers();
    236     }
    237
    238     /***
    239      * Returns the class loader that loaded this class.
    240      *
    241      * @return the class loader
    242      */
    243     public ClassLoader getClassLoader() {
    244         return m_class.getClassLoader();
    245     }
    246
    247     /***
    248      * Returns a constructor info by its hash.
    249      *
    250      * @param hash
    251      * @return
    252      */
    253     public ConstructorInfo getConstructor(final int hash) {
    254         ConstructorInfo constructor = (ConstructorInfo) m_constructors.get(hash);
    255         if (constructor == null && getSuperclass() != null) {
    256             constructor = getSuperclass().getConstructor(hash);
    257         }
    258         return constructor;
    259     }
    260
    261     /***
    262      * Returns a list with all the constructors info.
    263      *
    264      * @return the constructors info
    265      */
    266     public ConstructorInfo[] getConstructors() {
    267         Object[] values = m_constructors.getValues();
    268         ConstructorInfo[] methodInfos = new ConstructorInfo[values.length];
    269         for (int i = 0; i < values.length; i++) {
    270             methodInfos[i] = (ConstructorInfo) values[i];
    271         }
    272         return methodInfos;
    273     }
    274
    275     /***
    276      * Returns a method info by its hash.
    277      *
    278      * @param hash
    279      * @return
    280      */
    281     public MethodInfo getMethod(final int hash) {
    282         MethodInfo method = (MethodInfo) m_methods.get(hash);
    283         if (method == null) {
    284             for (int i = 0; i < getInterfaces().length; i++) {
    285                 method = getInterfaces()[i].getMethod(hash);
    286                 if (method != null) {
    287                     break;
    288                 }
    289             }
    290         }
    291         if (method == null && getSuperclass() != null) {
    292             method = getSuperclass().getMethod(hash);
    293         }
    294         return method;
    295     }
    296
    297     /***
    298      * Returns a list with all the methods info.
    299      *
    300      * @return the methods info
    301      */
    302     public MethodInfo[] getMethods() {
    303         Object[] values = m_methods.getValues();
    304         MethodInfo[] methodInfos = new MethodInfo[values.length];
    305         for (int i = 0; i < values.length; i++) {
    306             methodInfos[i] = (MethodInfo) values[i];
    307         }
    308         return methodInfos;
    309     }
    310
    311     /***
    312      * Returns a field info by its hash.
    313      *
    314      * @param hash
    315      * @return
    316      */
    317     public FieldInfo getField(final int hash) {
    318         FieldInfo field = (FieldInfo) m_fields.get(hash);
    319         if (field == null && getSuperclass() != null) {
    320             field = getSuperclass().getField(hash);
    321         }
    322         return field;
    323     }
    324
    325     /***
    326      * Returns a list with all the field info.
    327      *
    328      * @return the field info
    329      */
    330     public FieldInfo[] getFields() {
    331         Object[] values = m_fields.getValues();
    332         FieldInfo[] fieldInfos = new FieldInfo[values.length];
    333         for (int i = 0; i < values.length; i++) {
    334             fieldInfos[i] = (FieldInfo) values[i];
    335         }
    336         return fieldInfos;
    337     }
    338
    339     /***
    340      * Returns the interfaces.
    341      *
    342      * @return the interfaces
    343      */
    344     public ClassInfo[] getInterfaces() {
    345         if (m_interfaces == null) {
    346             Class[] interfaces = m_class.getInterfaces();
    347             m_interfaces = new ClassInfo[interfaces.length];
    348             for (int i = 0; i < interfaces.length; i++) {
    349                 Class anInterface = interfaces[i];
    350                 ClassInfo classInfo = JavaClassInfo.getClassInfo(anInterface);
    351                 m_interfaces[i] = classInfo;
    352                 if (!m_classInfoRepository.hasClassInfo(anInterface.getName())) {
    353                     m_classInfoRepository.addClassInfo(classInfo);
    354                 }
    355             }
    356         }
    357         return m_interfaces;
    358     }
    359
    360     /***
    361      * Returns the super class.
    362      *
    363      * @return the super class
    364      */
    365     public ClassInfo getSuperclass() {
    366         if (m_superClass == null) {
    367             Class superclass = m_class.getSuperclass();
    368             if (superclass != null) {
    369                 if (m_classInfoRepository.hasClassInfo(superclass.getName())) {
    370                     m_superClass = m_classInfoRepository.getClassInfo(superclass.getName());
    371                 } else {
    372                     m_superClass = JavaClassInfo.getClassInfo(superclass);
    373                     m_classInfoRepository.addClassInfo(m_superClass);
    374                 }
    375             }
    376         }
    377         return m_superClass;
    378     }
    379
    380     /***
    381      * Returns the component type if array type else null.
    382      *
    383      * @return the component type
    384      */
    385     public ClassInfo getComponentType() {
    386         if (isArray() && (m_componentType == null)) {
    387             Class componentType = m_class.getComponentType();
    388             if (m_classInfoRepository.hasClassInfo(componentType.getName())) {
    389                 m_componentType = m_classInfoRepository.getClassInfo(componentType.getName());
    390             } else {
    391                 m_componentType = JavaClassInfo.getClassInfo(componentType);
    392                 m_classInfoRepository.addClassInfo(m_componentType);
    393             }
    394         }
    395         return m_componentType;
    396     }
    397
    398     /***
    399      * Is the class an interface.
    400      *
    401      * @return
    402      */
    403     public boolean isInterface() {
    404         return m_isInterface;
    405     }
    406
    407     /***
    408      * Is the class a primitive type.
    409      *
    410      * @return
    411      */
    412     public boolean isPrimitive() {
    413         return m_isPrimitive;
    414     }
    415
    416     /***
    417      * Is the class an array type.
    418      *
    419      * @return
    420      */
    421     public boolean isArray() {
    422         return m_isArray;
    423     }
    424
    425     /***
    426      * Converts an internal Java array type name ([Lblabla) to the a the format used by the expression matcher
    427      * (blabla[])
    428      *
    429      * @param typeName is type name
    430      * @return
    431      */
    432     public static String convertJavaArrayTypeNameToHumanTypeName(final String typeName) {
    433         int index = typeName.lastIndexOf('[');
    434         if (index != -1) {
    435             StringBuffer arrayType = new StringBuffer();
    436             if (typeName.endsWith("I")) {
    437                 arrayType.append("int");
    438             } else if (typeName.endsWith("J")) {
    439                 arrayType.append("long");
    440             } else if (typeName.endsWith("S")) {
    441                 arrayType.append("short");
    442             } else if (typeName.endsWith("F")) {
    443                 arrayType.append("float");
    444             } else if (typeName.endsWith("D")) {
    445                 arrayType.append("double");
    446             } else if (typeName.endsWith("Z")) {
    447                 arrayType.append("boolean");
    448             } else if (typeName.endsWith("C")) {
    449                 arrayType.append("char");
    450             } else if (typeName.endsWith("B")) {
    451                 arrayType.append("byte");
    452             } else {
    453                 arrayType.append(typeName.substring(index + 2, typeName.length() - 1));
    454             }
    455             for (int i = 0; i < (index + 1); i++) {
    456                 arrayType.append("[]");
    457             }
    458             return arrayType.toString();
    459         } else {
    460             return typeName;
    461         }
    462     }
    463
    464     public boolean equals(Object o) {
    465         if (this == o) {
    466             return true;
    467         }
    468         if (!(o instanceof ClassInfo)) {
    469             return false;
    470         }
    471         ClassInfo classInfo = (ClassInfo) o;
    472         return m_class.getName().toString().equals(classInfo.getName().toString());
    473     }
    474
    475     public int hashCode() {
    476         return m_class.getName().toString().hashCode();
    477     }
    478
    479     public String toString() {
    480         return getName();
    481     }
    482 }