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
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
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
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
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
170
171
172
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 }