001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.reflect;
005:
006: import java.lang.reflect.Constructor;
007: import java.lang.reflect.Field;
008: import java.lang.reflect.Modifier;
009: import java.lang.reflect.Method;
010: import java.util.List;
011: import java.util.Iterator;
012:
013: import com.tc.aspectwerkz.exception.WrappedRuntimeException;
014: import com.tc.aspectwerkz.transform.TransformationConstants;
015:
016: /**
017: * Helper class with utility methods for working with the java.lang.reflect.* package.
018: *
019: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
020: */
021: public class ReflectHelper {
022:
023: private final static Method OBJECT_EQUALS;
024: private final static Method OBJECT_HASH_CODE;
025: private final static Method OBJECT_GET_CLASS;
026: private final static Method OBJECT_TO_STRING;
027: private final static Method OBJECT_CLONE;
028: private final static Method OBJECT_WAIT_1;
029: private final static Method OBJECT_WAIT_2;
030: private final static Method OBJECT_WAIT_3;
031: private final static Method OBJECT_NOTIFY;
032: private final static Method OBJECT_NOTIFY_ALL;
033: private final static Method OBJECT_FINALIZE;
034:
035: static {
036: Class clazz = Object.class;
037: try {
038: OBJECT_EQUALS = clazz.getDeclaredMethod("equals",
039: new Class[] { clazz });
040: OBJECT_HASH_CODE = clazz.getDeclaredMethod("hashCode",
041: new Class[] {});
042: OBJECT_GET_CLASS = clazz.getDeclaredMethod("getClass",
043: new Class[] {});
044: OBJECT_CLONE = clazz.getDeclaredMethod("clone",
045: new Class[] {});
046: OBJECT_TO_STRING = clazz.getDeclaredMethod("toString",
047: new Class[] {});
048: OBJECT_WAIT_1 = clazz.getDeclaredMethod("wait",
049: new Class[] {});
050: OBJECT_WAIT_2 = clazz.getDeclaredMethod("wait",
051: new Class[] { long.class });
052: OBJECT_WAIT_3 = clazz.getDeclaredMethod("wait",
053: new Class[] { long.class, int.class });
054: OBJECT_NOTIFY = clazz.getDeclaredMethod("notify",
055: new Class[] {});
056: OBJECT_NOTIFY_ALL = clazz.getDeclaredMethod("notifyAll",
057: new Class[] {});
058: OBJECT_FINALIZE = clazz.getDeclaredMethod("finalize",
059: new Class[] {});
060: } catch (NoSuchMethodException e) {
061: throw new WrappedRuntimeException(e);
062: }
063: }
064:
065: // /**
066: // * Creates a sorted method list of all the methods in the class and super classes, including package private ones.
067: // *
068: // * @param klass the class with the methods
069: // * @return the sorted method list
070: // */
071: // public static List createSortedMethodList(final Class klass) {
072: // if (klass == null) {
073: // throw new IllegalArgumentException("class to sort method on can not be null");
074: // }
075: //
076: // // getDefault all public methods including the inherited methods
077: // java.lang.reflect.Method[] methods = klass.getMethods();
078: // java.lang.reflect.Method[] privateMethods = klass.getDeclaredMethods();
079: // List methodList = new ArrayList(methods.length);
080: // for (int i = 0; i < methods.length; i++) {
081: // Method method = methods[i];
082: // if (ReflectHelper.isUserDefinedMethod(method)) {
083: // methodList.add(method);
084: // }
085: // }
086: // // lookup in declared method to add "package private" method (which can be Pointcut with signatures)
087: // for (int i = 0; i < privateMethods.length; i++) {
088: // Method method = privateMethods[i];
089: // if (ReflectHelper.isUserDefinedMethod(method) && !methodList.contains(method)) {
090: // methodList.add(method);
091: // }
092: // }
093: //
094: // Collections.sort(methodList, MethodComparator.getInstance(MethodComparator.NORMAL_METHOD));
095: // return methodList;
096: // }
097:
098: // /**
099: // * Creates a sorted method list of all the methods in the class and super classes, if and only
100: // * if those are part of the given list of interfaces declared method
101: // *
102: // * @param klass the class with the methods
103: // * @param interfaceDeclaredMethods the list of interface declared methods
104: // * @return the sorted method list
105: // */
106: // public static List createInterfaceDefinedSortedMethodList(final Class klass, List interfaceDeclaredMethods) {
107: // if (klass == null) {
108: // throw new IllegalArgumentException("class to sort method on can not be null");
109: // }
110: //
111: // // getDefault all public methods including the inherited methods
112: // java.lang.reflect.Method[] methods = klass.getMethods();
113: // java.lang.reflect.Method[] privateMethods = klass.getDeclaredMethods();
114: // List methodList = new ArrayList(methods.length);
115: // for (int i = 0; i < methods.length; i++) {
116: // Method method = methods[i];
117: // if (ReflectHelper.isUserDefinedMethod(method) && isDeclaredByInterface(method, interfaceDeclaredMethods)) {
118: // methodList.add(method);
119: // }
120: // }
121: // // lookup in declared method to add "package private" method (which can be Pointcut with signatures)
122: // for (int i = 0; i < privateMethods.length; i++) {
123: // Method method = privateMethods[i];
124: // if (ReflectHelper.isUserDefinedMethod(method) && isDeclaredByInterface(method, interfaceDeclaredMethods)
125: // && !methodList.contains(method)) {
126: // methodList.add(method);
127: // }
128: // }
129: //
130: // Collections.sort(methodList, MethodComparator.getInstance(MethodComparator.NORMAL_METHOD));
131: // return methodList;
132: // }
133:
134: /**
135: * Returns true if the method is declared by one of the given method declared in an interface class
136: *
137: * @param method
138: * @param interfaceDeclaredMethods
139: * @return
140: */
141: private static boolean isDeclaredByInterface(Method method,
142: List interfaceDeclaredMethods) {
143: boolean match = false;
144: for (Iterator iterator = interfaceDeclaredMethods.iterator(); iterator
145: .hasNext();) {
146: Method methodIt = (Method) iterator.next();
147: if (method.getName().equals(methodIt.getName())) {
148: if (method.getParameterTypes().length == methodIt
149: .getParameterTypes().length) {
150: boolean matchArgs = true;
151: for (int i = 0; i < method.getParameterTypes().length; i++) {
152: // BAD ! will lead to nested loading while system not ready
153: // => if introduced method has target class in its signature weaving will not occur
154: // properly
155: // ?? should we use ASMInfo ?
156: Class parameterType = method
157: .getParameterTypes()[i];
158: if (parameterType.getName().equals(
159: methodIt.getParameterTypes()[i]
160: .getName())) {
161: ;
162: } else {
163: matchArgs = false;
164: break;
165: }
166: }
167: if (matchArgs) {
168: match = true;
169: break;
170: }
171: }
172: }
173: }
174: return match;
175: }
176:
177: /**
178: * Returns true if the method is not of on java.lang.Object and is not an AW generated one
179: *
180: * @param method
181: * @return
182: */
183: private static boolean isUserDefinedMethod(final Method method) {
184: if (!method.equals(OBJECT_EQUALS)
185: && !method.equals(OBJECT_HASH_CODE)
186: && !method.equals(OBJECT_GET_CLASS)
187: && !method.equals(OBJECT_TO_STRING)
188: && !method.equals(OBJECT_CLONE)
189: && !method.equals(OBJECT_WAIT_1)
190: && !method.equals(OBJECT_WAIT_2)
191: && !method.equals(OBJECT_WAIT_3)
192: && !method.equals(OBJECT_NOTIFY)
193: && !method.equals(OBJECT_NOTIFY_ALL)
194: && !method
195: .getName()
196: .startsWith(
197: TransformationConstants.SYNTHETIC_MEMBER_PREFIX)
198: && !method.getName().startsWith(
199: TransformationConstants.ORIGINAL_METHOD_PREFIX)
200: && !method.getName().startsWith(
201: TransformationConstants.ASPECTWERKZ_PREFIX)) {
202: return true;
203: } else {
204: return false;
205: }
206: }
207:
208: /**
209: * Converts modifiers represented in a string array to an int.
210: *
211: * @param modifiers the modifiers as strings
212: * @return the modifiers as an int
213: */
214: public static int getModifiersAsInt(final String[] modifiers) {
215: int accessFlags = 0;
216: for (int i = 0; i < modifiers.length; i++) {
217: if (modifiers[i].equals("abstract")) {
218: accessFlags |= Modifier.ABSTRACT;
219: } else if (modifiers[i].equals("final")) {
220: accessFlags |= Modifier.FINAL;
221: } else if (modifiers[i].equals("interface")) {
222: accessFlags |= Modifier.INTERFACE;
223: } else if (modifiers[i].equals("native")) {
224: accessFlags |= Modifier.NATIVE;
225: } else if (modifiers[i].equals("private")) {
226: accessFlags |= Modifier.PRIVATE;
227: } else if (modifiers[i].equals("protected")) {
228: accessFlags |= Modifier.PROTECTED;
229: } else if (modifiers[i].equals("public")) {
230: accessFlags |= Modifier.PUBLIC;
231: } else if (modifiers[i].equals("static")) {
232: accessFlags |= Modifier.STATIC;
233: } else if (modifiers[i].equals("strict")) {
234: accessFlags |= Modifier.STRICT;
235: } else if (modifiers[i].equals("synchronized")) {
236: accessFlags |= Modifier.SYNCHRONIZED;
237: } else if (modifiers[i].equals("transient")) {
238: accessFlags |= Modifier.TRANSIENT;
239: } else if (modifiers[i].equals("volatile")) {
240: accessFlags |= Modifier.VOLATILE;
241: }
242: }
243: return accessFlags;
244: }
245:
246: /**
247: * Calculate the hash for a class.
248: *
249: * @param klass the class
250: * @return the hash
251: */
252: public static int calculateHash(final Class klass) {
253: return klass.getName().hashCode();
254: }
255:
256: /**
257: * Calculate the hash for a method.
258: *
259: * @param method the method
260: * @return the hash
261: */
262: public static int calculateHash(final Method method) {
263: int hash = 17;
264: hash = (37 * hash) + method.getName().hashCode();
265: for (int i = 0; i < method.getParameterTypes().length; i++) {
266: Class type = method.getParameterTypes()[i];
267: hash = (37 * hash) + type.getName().hashCode();
268: }
269: return hash;
270: }
271:
272: /**
273: * Calculate the hash for a constructor.
274: *
275: * @param constructor the constructor
276: * @return the hash
277: */
278: public static int calculateHash(final Constructor constructor) {
279: int hash = 17;
280: hash = (37 * hash)
281: + TransformationConstants.INIT_METHOD_NAME.hashCode();
282: for (int i = 0; i < constructor.getParameterTypes().length; i++) {
283: Class type = constructor.getParameterTypes()[i];
284: hash = (37 * hash)
285: + type.getName().replace('/', '.').hashCode();
286: }
287: return hash;
288: }
289:
290: /**
291: * Calculate the hash for a field.
292: *
293: * @param field the field
294: * @return the hash
295: */
296: public static int calculateHash(final Field field) {
297: int hash = 17;
298: hash = (37 * hash) + field.getName().hashCode();
299: Class type = field.getType();
300: hash = (37 * hash) + type.getName().hashCode();
301: return hash;
302: }
303:
304: /**
305: * Checks if the class is a of a primitive type, if so create and return the class for the type else return null.
306: *
307: * @param className
308: * @return the class for the primitive type or null
309: */
310: public static Class getPrimitiveClass(final String className) {
311: if (className.equals("void")) {
312: return void.class;
313: } else if (className.equals("long")) {
314: return long.class;
315: } else if (className.equals("int")) {
316: return int.class;
317: } else if (className.equals("short")) {
318: return short.class;
319: } else if (className.equals("double")) {
320: return double.class;
321: } else if (className.equals("float")) {
322: return float.class;
323: } else if (className.equals("byte")) {
324: return byte.class;
325: } else if (className.equals("boolean")) {
326: return boolean.class;
327: } else if (className.equals("char")) {
328: return char.class;
329: } else {
330: return null;
331: }
332: }
333:
334: /**
335: * Returns JVM type signature for given class.
336: *
337: * @param cl
338: * @return
339: */
340: public static String getClassSignature(Class cl) {
341: StringBuffer sbuf = new StringBuffer();
342: while (cl.isArray()) {
343: sbuf.append('[');
344: cl = cl.getComponentType();
345: }
346: if (cl.isPrimitive()) {
347: if (cl == Integer.TYPE) {
348: sbuf.append('I');
349: } else if (cl == Byte.TYPE) {
350: sbuf.append('B');
351: } else if (cl == Long.TYPE) {
352: sbuf.append('J');
353: } else if (cl == Float.TYPE) {
354: sbuf.append('F');
355: } else if (cl == Double.TYPE) {
356: sbuf.append('D');
357: } else if (cl == Short.TYPE) {
358: sbuf.append('S');
359: } else if (cl == Character.TYPE) {
360: sbuf.append('C');
361: } else if (cl == Boolean.TYPE) {
362: sbuf.append('Z');
363: } else if (cl == Void.TYPE) {
364: sbuf.append('V');
365: } else {
366: throw new InternalError();
367: }
368: } else {
369: sbuf.append('L' + cl.getName().replace('.', '/') + ';');
370: }
371: return sbuf.toString();
372: }
373:
374: /**
375: * Returns JVM type signature for a constructor.
376: *
377: * @param constructor
378: * @return
379: */
380: public static String getConstructorSignature(
381: final Constructor constructor) {
382: return getMethodSignature(constructor.getParameterTypes(),
383: Void.TYPE);
384: }
385:
386: /**
387: * Returns JVM type signature for a field.
388: *
389: * @param field
390: * @return
391: */
392: public static String getFieldSignature(final Field field) {
393: return getClassSignature(field.getType());
394: }
395:
396: /**
397: * Returns JVM type signature for a method.
398: *
399: * @param method
400: * @return
401: */
402: public static String getMethodSignature(final Method method) {
403: return getMethodSignature(method.getParameterTypes(), method
404: .getReturnType());
405: }
406:
407: /**
408: * Returns JVM type signature for given list of parameters and return type.
409: *
410: * @param paramTypes
411: * @param retType
412: * @return
413: */
414: private static String getMethodSignature(Class[] paramTypes,
415: Class retType) {
416: StringBuffer sbuf = new StringBuffer();
417: sbuf.append('(');
418: for (int i = 0; i < paramTypes.length; i++) {
419: sbuf.append(getClassSignature(paramTypes[i]));
420: }
421: sbuf.append(')');
422: sbuf.append(getClassSignature(retType));
423: return sbuf.toString();
424: }
425: }
|