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