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.transform;
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.MethodComparator;
20  import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
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      static {
41          Class clazz = Object.class;
42          try {
43              OBJECT_EQUALS = clazz.getDeclaredMethod("equals", new Class[]{clazz});
44              OBJECT_HASH_CODE = clazz.getDeclaredMethod("hashCode", new Class[]{});
45              OBJECT_GET_CLASS = clazz.getDeclaredMethod("getClass", new Class[]{});
46              OBJECT_CLONE = clazz.getDeclaredMethod("clone", new Class[]{});
47              OBJECT_TO_STRING = clazz.getDeclaredMethod("toString", new Class[]{});
48              OBJECT_WAIT_1 = clazz.getDeclaredMethod("wait", new Class[]{});
49              OBJECT_WAIT_2 = clazz.getDeclaredMethod("wait", new Class[]{long.class});
50              OBJECT_WAIT_3 = clazz.getDeclaredMethod("wait", new Class[]{long.class, int.class});
51              OBJECT_NOTIFY = clazz.getDeclaredMethod("notify", new Class[]{});
52              OBJECT_NOTIFY_ALL = clazz.getDeclaredMethod("notifyAll", new Class[]{});
53              OBJECT_FINALIZE = clazz.getDeclaredMethod("finalize", new Class[]{});
54          } catch (NoSuchMethodException e) {
55              throw new WrappedRuntimeException(e);
56          }
57      }
58  
59      /***
60       * Creates a sorted method list of all the methods in the class and super classes, including package private ones.
61       *
62       * @param klass the class with the methods
63       * @return the sorted method list
64       */
65      public static List createCompleteSortedMethodList(final Class klass) {
66          if (klass == null) {
67              throw new IllegalArgumentException("class to sort method on can not be null");
68          }
69  
70          // get all public methods including the inherited methods
71          java.lang.reflect.Method[] methods = klass.getMethods();
72          java.lang.reflect.Method[] privateMethods = klass.getDeclaredMethods();
73          List methodList = new ArrayList(methods.length);
74          for (int i = 0; i < methods.length; i++) {
75              Method method = methods[i];
76              if (ReflectHelper.isUserDefinedMethod(method)) {
77                  methodList.add(method);
78              }
79          }
80          // lookup in declared method to add "package private" method (which can be Pointcut with signatures)
81          for (int i = 0; i < privateMethods.length; i++) {
82              Method method = privateMethods[i];
83              if (ReflectHelper.isUserDefinedMethod(method) && !methodList.contains(method)) {
84                  methodList.add(method);
85              }
86          }
87  
88          Collections.sort(methodList, MethodComparator.getInstance(MethodComparator.NORMAL_METHOD));
89          return methodList;
90      }
91  
92      /***
93       * Creates a sorted method list of all the methods in the class and super classes, if and only
94       * if those are part of the given list of interfaces declared method
95       *
96       * @param klass the class with the methods
97       * @param interfaceDeclaredMethods the list of interface declared methods
98       * @return the sorted method list
99       */
100     public static List createInterfaceDefinedSortedMethodList(final Class klass, List interfaceDeclaredMethods) {
101         if (klass == null) {
102             throw new IllegalArgumentException("class to sort method on can not be null");
103         }
104 
105         // get all public methods including the inherited methods
106         java.lang.reflect.Method[] methods = klass.getMethods();
107         java.lang.reflect.Method[] privateMethods = klass.getDeclaredMethods();
108         List methodList = new ArrayList(methods.length);
109         for (int i = 0; i < methods.length; i++) {
110             Method method = methods[i];
111             if (ReflectHelper.isUserDefinedMethod(method) && isDeclaredByInterface(method, interfaceDeclaredMethods)) {
112                 methodList.add(method);
113             }
114         }
115         // lookup in declared method to add "package private" method (which can be Pointcut with signatures)
116         for (int i = 0; i < privateMethods.length; i++) {
117             Method method = privateMethods[i];
118             if (ReflectHelper.isUserDefinedMethod(method) && isDeclaredByInterface(method, interfaceDeclaredMethods)
119                 && !methodList.contains(method)) {
120                 methodList.add(method);
121             }
122         }
123 
124         Collections.sort(methodList, MethodComparator.getInstance(MethodComparator.NORMAL_METHOD));
125         return methodList;
126     }
127 
128     /***
129      * Returns true if the method is not of on java.lang.Object and is not an AW generated one
130      *
131      * @param method
132      * @return
133      */
134     private static boolean isUserDefinedMethod(final Method method) {
135         if (!method.equals(OBJECT_EQUALS)
136             && !method.equals(OBJECT_HASH_CODE)
137             && !method.equals(OBJECT_GET_CLASS)
138             && !method.equals(OBJECT_TO_STRING)
139             && !method.equals(OBJECT_CLONE)
140             && !method.equals(OBJECT_WAIT_1)
141             && !method.equals(OBJECT_WAIT_2)
142             && !method.equals(OBJECT_WAIT_3)
143             && !method.equals(OBJECT_NOTIFY)
144             && !method.equals(OBJECT_NOTIFY_ALL)
145             && !method.getName().startsWith(TransformationConstants.CLASS_LOOKUP_METHOD)
146             && !method.getName().startsWith(TransformationConstants.ORIGINAL_METHOD_PREFIX)
147             && !method.getName().startsWith(TransformationConstants.ASPECTWERKZ_PREFIX)) {
148             return true;
149         } else {
150             return false;
151         }
152     }
153 
154     /***
155      * Returns true if the method is declared by one of the given method declared in an interface class
156      *
157      * @param method
158      * @param interfaceDeclaredMethods
159      * @return
160      */
161     private static boolean isDeclaredByInterface(Method method, List interfaceDeclaredMethods) {
162         boolean match = false;
163         for (Iterator iterator = interfaceDeclaredMethods.iterator(); iterator.hasNext();) {
164             Method methodIt = (Method) iterator.next();
165             if (method.getName().equals(methodIt.getName())) {
166                 if (method.getParameterTypes().length == methodIt.getParameterTypes().length) {
167                     boolean matchArgs = true;
168                     for (int i = 0; i < method.getParameterTypes().length; i++) {
169                         // BAD ! will lead to nested loading while system not ready
170                         // => if introduced method has target class in its signature weaving will not occur
171                         // properly
172                         // ?? should we use ASMInfo ?
173                         Class parameterType = method.getParameterTypes()[i];
174                         if (parameterType.getName().equals(methodIt.getParameterTypes()[i].getName())) {
175                             ;
176                         } else {
177                             matchArgs = false;
178                             break;
179                         }
180                     }
181                     if (matchArgs) {
182                         match = true;
183                         break;
184                     }
185                 }
186             }
187         }
188         return match;
189     }
190 
191     /***
192      * Converts modifiers represented in a string array to an int.
193      *
194      * @param modifiers the modifiers as strings
195      * @return the modifiers as an int
196      */
197     public static int getModifiersAsInt(final String[] modifiers) {
198         int accessFlags = 0;
199         for (int i = 0; i < modifiers.length; i++) {
200             if (modifiers[i].equals("abstract")) {
201                 accessFlags |= Modifier.ABSTRACT;
202             } else if (modifiers[i].equals("final")) {
203                 accessFlags |= Modifier.FINAL;
204             } else if (modifiers[i].equals("interface")) {
205                 accessFlags |= Modifier.INTERFACE;
206             } else if (modifiers[i].equals("native")) {
207                 accessFlags |= Modifier.NATIVE;
208             } else if (modifiers[i].equals("private")) {
209                 accessFlags |= Modifier.PRIVATE;
210             } else if (modifiers[i].equals("protected")) {
211                 accessFlags |= Modifier.PROTECTED;
212             } else if (modifiers[i].equals("public")) {
213                 accessFlags |= Modifier.PUBLIC;
214             } else if (modifiers[i].equals("static")) {
215                 accessFlags |= Modifier.STATIC;
216             } else if (modifiers[i].equals("strict")) {
217                 accessFlags |= Modifier.STRICT;
218             } else if (modifiers[i].equals("synchronized")) {
219                 accessFlags |= Modifier.SYNCHRONIZED;
220             } else if (modifiers[i].equals("transient")) {
221                 accessFlags |= Modifier.TRANSIENT;
222             } else if (modifiers[i].equals("volatile")) {
223                 accessFlags |= Modifier.VOLATILE;
224             }
225         }
226         return accessFlags;
227     }
228 
229     /***
230      * Calculate the hash for a class.
231      *
232      * @param klass the class
233      * @return the hash
234      */
235     public static int calculateHash(final Class klass) {
236         return klass.getName().hashCode();
237     }
238 
239     /***
240      * Calculate the hash for a method.
241      *
242      * @param method the method
243      * @return the hash
244      */
245     public static int calculateHash(final java.lang.reflect.Method method) {
246         int hash = 17;
247         hash = (37 * hash) + method.getName().hashCode();
248         for (int i = 0; i < method.getParameterTypes().length; i++) {
249             Class type = method.getParameterTypes()[i];
250             hash = (37 * hash) + type.getName().hashCode();
251         }
252         return hash;
253     }
254 
255     /***
256      * Calculate the hash for a constructor.
257      *
258      * @param constructor the constructor
259      * @return the hash
260      */
261     public static int calculateHash(final Constructor constructor) {
262         int hash = 17;
263         hash = (37 * hash) + TransformationConstants.INIT_METHOD_NAME.hashCode();
264         for (int i = 0; i < constructor.getParameterTypes().length; i++) {
265             Class type = constructor.getParameterTypes()[i];
266             hash = (37 * hash) + type.getName().replace('/', '.').hashCode();
267         }
268         return hash;
269     }
270 
271     /***
272      * Calculate the hash for a field.
273      *
274      * @param field the field
275      * @return the hash
276      */
277     public static int calculateHash(final Field field) {
278         int hash = 17;
279         hash = (37 * hash) + field.getName().hashCode();
280         Class type = field.getType();
281         hash = (37 * hash) + type.getName().hashCode();
282         return hash;
283     }
284 
285     /***
286      * Checks if the class is a of a primitive type, if so create and return the class for the type else return null.
287      *
288      * @param className
289      * @return the class for the primitive type or null
290      */
291     public static Class getPrimitiveClass(final String className) {
292         if (className.equals("void")) {
293             return void.class;
294         } else if (className.equals("long")) {
295             return long.class;
296         } else if (className.equals("int")) {
297             return int.class;
298         } else if (className.equals("short")) {
299             return short.class;
300         } else if (className.equals("double")) {
301             return double.class;
302         } else if (className.equals("float")) {
303             return float.class;
304         } else if (className.equals("byte")) {
305             return byte.class;
306         } else if (className.equals("boolean")) {
307             return boolean.class;
308         } else if (className.equals("char")) {
309             return char.class;
310         } else {
311             return null;
312         }
313     }
314 }