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 }