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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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
145
146
147
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 }