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;
    9
    10  import java.lang.reflect.Constructor;
    11  import java.lang.reflect.Field;
    12  import java.lang.reflect.Modifier;
    13  import java.lang.reflect.Method;
    14  import java.util.ArrayList;
    15  import java.util.Collections;
    16  import java.util.List;
    17  import java.util.Iterator;
    18
    19  import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
    20  import org.codehaus.aspectwerkz.transform.TransformationConstants;
    21
    22  /***
    23   * Helper class with utility methods for working with the java.lang.reflect.* package.
    24   *
    25   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    26   */
    27  public class ReflectHelper {
    28
    29      private final static Method OBJECT_EQUALS;
    30      private final static Method OBJECT_HASH_CODE;
    31      private final static Method OBJECT_GET_CLASS;
    32      private final static Method OBJECT_TO_STRING;
    33      private final static Method OBJECT_CLONE;
    34      private final static Method OBJECT_WAIT_1;
    35      private final static Method OBJECT_WAIT_2;
    36      private final static Method OBJECT_WAIT_3;
    37      private final static Method OBJECT_NOTIFY;
    38      private final static Method OBJECT_NOTIFY_ALL;
    39      private final static Method OBJECT_FINALIZE;
    40
    41      static {
    42          Class clazz = Object.class;
    43          try {
    44              OBJECT_EQUALS = clazz.getDeclaredMethod("equals", new Class[]{clazz});
    45              OBJECT_HASH_CODE = clazz.getDeclaredMethod("hashCode", new Class[]{});
    46              OBJECT_GET_CLASS = clazz.getDeclaredMethod("getClass", new Class[]{});
    47              OBJECT_CLONE = clazz.getDeclaredMethod("clone", new Class[]{});
    48              OBJECT_TO_STRING = clazz.getDeclaredMethod("toString", new Class[]{});
    49              OBJECT_WAIT_1 = clazz.getDeclaredMethod("wait", new Class[]{});
    50              OBJECT_WAIT_2 = clazz.getDeclaredMethod("wait", new Class[]{long.class});
    51              OBJECT_WAIT_3 = clazz.getDeclaredMethod("wait", new Class[]{long.class, int.class});
    52              OBJECT_NOTIFY = clazz.getDeclaredMethod("notify", new Class[]{});
    53              OBJECT_NOTIFY_ALL = clazz.getDeclaredMethod("notifyAll", new Class[]{});
    54              OBJECT_FINALIZE = clazz.getDeclaredMethod("finalize", new Class[]{});
    55          } catch (NoSuchMethodException e) {
    56              throw new WrappedRuntimeException(e);
    57          }
    58      }
    59
    60  //    /***
    61  //     * Creates a sorted method list of all the methods in the class and super classes, including package private ones.
    62  //     *
    63  //     * @param klass the class with the methods
    64  //     * @return the sorted method list
    65  //     */
    66  //    public static List createSortedMethodList(final Class klass) {
    67  //        if (klass == null) {
    68  //            throw new IllegalArgumentException("class to sort method on can not be null");
    69  //        }
    70  //
    71  //        // get all public methods including the inherited methods
    72  //        java.lang.reflect.Method[] methods = klass.getMethods();
    73  //        java.lang.reflect.Method[] privateMethods = klass.getDeclaredMethods();
    74  //        List methodList = new ArrayList(methods.length);
    75  //        for (int i = 0; i < methods.length; i++) {
    76  //            Method method = methods[i];
    77  //            if (ReflectHelper.isUserDefinedMethod(method)) {
    78  //                methodList.add(method);
    79  //            }
    80  //        }
    81  //        // lookup in declared method to add "package private" method (which can be Pointcut with signatures)
    82  //        for (int i = 0; i < privateMethods.length; i++) {
    83  //            Method method = privateMethods[i];
    84  //            if (ReflectHelper.isUserDefinedMethod(method) && !methodList.contains(method)) {
    85  //                methodList.add(method);
    86  //            }
    87  //        }
    88  //
    89  //        Collections.sort(methodList, MethodComparator.getInstance(MethodComparator.NORMAL_METHOD));
    90  //        return methodList;
    91  //    }
    92
    93  //    /***
    94  //     * Creates a sorted method list of all the methods in the class and super classes, if and only
    95  //     * if those are part of the given list of interfaces declared method
    96  //     *
    97  //     * @param klass                    the class with the methods
    98  //     * @param interfaceDeclaredMethods the list of interface declared methods
    99  //     * @return the sorted method list
    100 //     */
    101 //    public static List createInterfaceDefinedSortedMethodList(final Class klass, List interfaceDeclaredMethods) {
    102 //        if (klass == null) {
    103 //            throw new IllegalArgumentException("class to sort method on can not be null");
    104 //        }
    105 //
    106 //        // get all public methods including the inherited methods
    107 //        java.lang.reflect.Method[] methods = klass.getMethods();
    108 //        java.lang.reflect.Method[] privateMethods = klass.getDeclaredMethods();
    109 //        List methodList = new ArrayList(methods.length);
    110 //        for (int i = 0; i < methods.length; i++) {
    111 //            Method method = methods[i];
    112 //            if (ReflectHelper.isUserDefinedMethod(method) && isDeclaredByInterface(method, interfaceDeclaredMethods)) {
    113 //                methodList.add(method);
    114 //            }
    115 //        }
    116 //        // lookup in declared method to add "package private" method (which can be Pointcut with signatures)
    117 //        for (int i = 0; i < privateMethods.length; i++) {
    118 //            Method method = privateMethods[i];
    119 //            if (ReflectHelper.isUserDefinedMethod(method) && isDeclaredByInterface(method, interfaceDeclaredMethods)
    120 //                && !methodList.contains(method)) {
    121 //                methodList.add(method);
    122 //            }
    123 //        }
    124 //
    125 //        Collections.sort(methodList, MethodComparator.getInstance(MethodComparator.NORMAL_METHOD));
    126 //        return methodList;
    127 //    }
    128
    129     /***
    130      * Returns true if the method is declared by one of the given method declared in an interface class
    131      *
    132      * @param method
    133      * @param interfaceDeclaredMethods
    134      * @return
    135      */
    136     private static boolean isDeclaredByInterface(Method method, List interfaceDeclaredMethods) {
    137         boolean match = false;
    138         for (Iterator iterator = interfaceDeclaredMethods.iterator(); iterator.hasNext();) {
    139             Method methodIt = (Method) iterator.next();
    140             if (method.getName().equals(methodIt.getName())) {
    141                 if (method.getParameterTypes().length == methodIt.getParameterTypes().length) {
    142                     boolean matchArgs = true;
    143                     for (int i = 0; i < method.getParameterTypes().length; i++) {
    144                         // BAD ! will lead to nested loading while system not ready
    145                         // => if introduced method has target class in its signature weaving will not occur
    146                         // properly
    147                         // ?? should we use ASMInfo ?
    148                         Class parameterType = method.getParameterTypes()[i];
    149                         if (parameterType.getName().equals(methodIt.getParameterTypes()[i].getName())) {
    150                             ;
    151                         } else {
    152                             matchArgs = false;
    153                             break;
    154                         }
    155                     }
    156                     if (matchArgs) {
    157                         match = true;
    158                         break;
    159                     }
    160                 }
    161             }
    162         }
    163         return match;
    164     }
    165
    166     /***
    167      * Returns true if the method is not of on java.lang.Object and is not an AW generated one
    168      *
    169      * @param method
    170      * @return
    171      */
    172     private static boolean isUserDefinedMethod(final Method method) {
    173         if (!method.equals(OBJECT_EQUALS)
    174             && !method.equals(OBJECT_HASH_CODE)
    175             && !method.equals(OBJECT_GET_CLASS)
    176             && !method.equals(OBJECT_TO_STRING)
    177             && !method.equals(OBJECT_CLONE)
    178             && !method.equals(OBJECT_WAIT_1)
    179             && !method.equals(OBJECT_WAIT_2)
    180             && !method.equals(OBJECT_WAIT_3)
    181             && !method.equals(OBJECT_NOTIFY)
    182             && !method.equals(OBJECT_NOTIFY_ALL)
    183             && !method.getName().startsWith(TransformationConstants.SYNTHETIC_MEMBER_PREFIX)
    184             && !method.getName().startsWith(TransformationConstants.ORIGINAL_METHOD_PREFIX)
    185             && !method.getName().startsWith(TransformationConstants.ASPECTWERKZ_PREFIX)) {
    186             return true;
    187         } else {
    188             return false;
    189         }
    190     }
    191
    192     /***
    193      * Converts modifiers represented in a string array to an int.
    194      *
    195      * @param modifiers the modifiers as strings
    196      * @return the modifiers as an int
    197      */
    198     public static int getModifiersAsInt(final String[] modifiers) {
    199         int accessFlags = 0;
    200         for (int i = 0; i < modifiers.length; i++) {
    201             if (modifiers[i].equals("abstract")) {
    202                 accessFlags |= Modifier.ABSTRACT;
    203             } else if (modifiers[i].equals("final")) {
    204                 accessFlags |= Modifier.FINAL;
    205             } else if (modifiers[i].equals("interface")) {
    206                 accessFlags |= Modifier.INTERFACE;
    207             } else if (modifiers[i].equals("native")) {
    208                 accessFlags |= Modifier.NATIVE;
    209             } else if (modifiers[i].equals("private")) {
    210                 accessFlags |= Modifier.PRIVATE;
    211             } else if (modifiers[i].equals("protected")) {
    212                 accessFlags |= Modifier.PROTECTED;
    213             } else if (modifiers[i].equals("public")) {
    214                 accessFlags |= Modifier.PUBLIC;
    215             } else if (modifiers[i].equals("static")) {
    216                 accessFlags |= Modifier.STATIC;
    217             } else if (modifiers[i].equals("strict")) {
    218                 accessFlags |= Modifier.STRICT;
    219             } else if (modifiers[i].equals("synchronized")) {
    220                 accessFlags |= Modifier.SYNCHRONIZED;
    221             } else if (modifiers[i].equals("transient")) {
    222                 accessFlags |= Modifier.TRANSIENT;
    223             } else if (modifiers[i].equals("volatile")) {
    224                 accessFlags |= Modifier.VOLATILE;
    225             }
    226         }
    227         return accessFlags;
    228     }
    229
    230     /***
    231      * Calculate the hash for a class.
    232      *
    233      * @param klass the class
    234      * @return the hash
    235      */
    236     public static int calculateHash(final Class klass) {
    237         return klass.getName().hashCode();
    238     }
    239
    240     /***
    241      * Calculate the hash for a method.
    242      *
    243      * @param method the method
    244      * @return the hash
    245      */
    246     public static int calculateHash(final java.lang.reflect.Method method) {
    247         int hash = 17;
    248         hash = (37 * hash) + method.getName().hashCode();
    249         for (int i = 0; i < method.getParameterTypes().length; i++) {
    250             Class type = method.getParameterTypes()[i];
    251             hash = (37 * hash) + type.getName().hashCode();
    252         }
    253         return hash;
    254     }
    255
    256     /***
    257      * Calculate the hash for a constructor.
    258      *
    259      * @param constructor the constructor
    260      * @return the hash
    261      */
    262     public static int calculateHash(final Constructor constructor) {
    263         int hash = 17;
    264         hash = (37 * hash) + TransformationConstants.INIT_METHOD_NAME.hashCode();
    265         for (int i = 0; i < constructor.getParameterTypes().length; i++) {
    266             Class type = constructor.getParameterTypes()[i];
    267             hash = (37 * hash) + type.getName().replace('/', '.').hashCode();
    268         }
    269         return hash;
    270     }
    271
    272     /***
    273      * Calculate the hash for a field.
    274      *
    275      * @param field the field
    276      * @return the hash
    277      */
    278     public static int calculateHash(final Field field) {
    279         int hash = 17;
    280         hash = (37 * hash) + field.getName().hashCode();
    281         Class type = field.getType();
    282         hash = (37 * hash) + type.getName().hashCode();
    283         return hash;
    284     }
    285
    286     /***
    287      * Checks if the class is a of a primitive type, if so create and return the class for the type else return null.
    288      *
    289      * @param className
    290      * @return the class for the primitive type or null
    291      */
    292     public static Class getPrimitiveClass(final String className) {
    293         if (className.equals("void")) {
    294             return void.class;
    295         } else if (className.equals("long")) {
    296             return long.class;
    297         } else if (className.equals("int")) {
    298             return int.class;
    299         } else if (className.equals("short")) {
    300             return short.class;
    301         } else if (className.equals("double")) {
    302             return double.class;
    303         } else if (className.equals("float")) {
    304             return float.class;
    305         } else if (className.equals("byte")) {
    306             return byte.class;
    307         } else if (className.equals("boolean")) {
    308             return boolean.class;
    309         } else if (className.equals("char")) {
    310             return char.class;
    311         } else {
    312             return null;
    313         }
    314     }
    315
    316     /***
    317      * Returns JVM type signature for given class.
    318      *
    319      * @param cl
    320      * @return
    321      */
    322     public static String getClassSignature(Class cl) {
    323         StringBuffer sbuf = new StringBuffer();
    324         while (cl.isArray()) {
    325             sbuf.append('[');
    326             cl = cl.getComponentType();
    327         }
    328         if (cl.isPrimitive()) {
    329             if (cl == Integer.TYPE) {
    330                 sbuf.append('I');
    331             } else if (cl == Byte.TYPE) {
    332                 sbuf.append('B');
    333             } else if (cl == Long.TYPE) {
    334                 sbuf.append('J');
    335             } else if (cl == Float.TYPE) {
    336                 sbuf.append('F');
    337             } else if (cl == Double.TYPE) {
    338                 sbuf.append('D');
    339             } else if (cl == Short.TYPE) {
    340                 sbuf.append('S');
    341             } else if (cl == Character.TYPE) {
    342                 sbuf.append('C');
    343             } else if (cl == Boolean.TYPE) {
    344                 sbuf.append('Z');
    345             } else if (cl == Void.TYPE) {
    346                 sbuf.append('V');
    347             } else {
    348                 throw new InternalError();
    349             }
    350         } else {
    351             sbuf.append('L' + cl.getName().replace('.', '/') + ';');
    352         }
    353         return sbuf.toString();
    354     }
    355
    356     /***
    357      * Returns JVM type signature for a constructor.
    358      *
    359      * @param constructor
    360      * @return
    361      */
    362     public static String getConstructorSignature(final Constructor constructor) {
    363         return getMethodSignature(constructor.getParameterTypes(), Void.TYPE);
    364     }
    365
    366     /***
    367      * Returns JVM type signature for a field.
    368      *
    369      * @param field
    370      * @return
    371      */
    372     public static String getFieldSignature(final Field field) {
    373         return getClassSignature(field.getType());
    374     }
    375
    376     /***
    377      * Returns JVM type signature for a method.
    378      *
    379      * @param method
    380      * @return
    381      */
    382     public static String getMethodSignature(final Method method) {
    383         return getMethodSignature(method.getParameterTypes(), method.getReturnType());
    384     }
    385
    386     /***
    387      * Returns JVM type signature for given list of parameters and return type.
    388      *
    389      * @param paramTypes
    390      * @param retType
    391      * @return
    392      */
    393     private static String getMethodSignature(Class[] paramTypes, Class retType) {
    394         StringBuffer sbuf = new StringBuffer();
    395         sbuf.append('(');
    396         for (int i = 0; i < paramTypes.length; i++) {
    397             sbuf.append(getClassSignature(paramTypes[i]));
    398         }
    399         sbuf.append(')');
    400         sbuf.append(getClassSignature(retType));
    401         return sbuf.toString();
    402     }
    403 }