001: package com.mockrunner.util.common;
002:
003: import java.lang.reflect.Method;
004: import java.lang.reflect.Modifier;
005: import java.util.ArrayList;
006: import java.util.Arrays;
007: import java.util.HashSet;
008: import java.util.List;
009: import java.util.Set;
010:
011: import com.mockrunner.base.NestedApplicationException;
012:
013: public class MethodUtil {
014: /**
015: * Invokes the method with the specified name on the specified object
016: * and throws a {@link com.mockrunner.base.NestedApplicationException},
017: * if the invocation fails. The method must be public and must not
018: * have any parameters.
019: * @param object the object the method is invoked from
020: * @param methodName the name of the method
021: * @return the result of the method invocation
022: */
023: public static Object invoke(Object object, String methodName) {
024: try {
025: Method method = object.getClass().getMethod(methodName,
026: null);
027: return method.invoke(object, null);
028: } catch (Exception exc) {
029: throw new NestedApplicationException(exc);
030: }
031: }
032:
033: /**
034: * Invokes the method with the specified name on the specified object
035: * and throws a {@link com.mockrunner.base.NestedApplicationException},
036: * if the invocation fails. The method must be public and must have
037: * exactly one paremeter of the type specified by the given
038: * <code>parameter</code>.
039: * @param object the object the method is invoked from
040: * @param methodName the name of the method
041: * @param parameter the parameter, must not be <code>null</code>
042: * @return the result of the method invocation
043: */
044: public static Object invoke(Object object, String methodName,
045: Object parameter) {
046: try {
047: Method method = object.getClass().getMethod(methodName,
048: new Class[] { parameter.getClass() });
049: return method.invoke(object, new Object[] { parameter });
050: } catch (Exception exc) {
051: throw new NestedApplicationException(exc);
052: }
053: }
054:
055: /**
056: * Returns if the two specified methods are equal as
057: * defined by <code>Method.equals()</code> except that
058: * the methods can be defined by different classes.
059: * @param method1 the first method to compare
060: * @param method2 the second method to compare
061: * @return <code>true</code> if the methods are equal, <code>false</code>
062: * otherwise
063: * @throws NullPointerException if one of the methods is <code>null</code>
064: */
065: public static boolean areMethodsEqual(Method method1, Method method2) {
066: if (method1.equals(method2))
067: return true;
068: if (!method2.getName().equals(method1.getName()))
069: return false;
070: if (!method1.getReturnType().equals(method2.getReturnType()))
071: return false;
072: return Arrays.equals(method1.getParameterTypes(), method2
073: .getParameterTypes());
074: }
075:
076: /**
077: * Returns if <code>method2</code> overrides <code>method1</code>.
078: * @param method1 method to be overridden
079: * @param method2 overriding method
080: * @return <code>true</code> if <code>method2</code> overrides <code>method1</code>, <code>false</code>
081: * otherwise
082: * @throws NullPointerException if one of the methods is <code>null</code>
083: */
084: public static boolean overrides(Method method1, Method method2) {
085: if (method1.equals(method2))
086: return false;
087: if (!method1.getDeclaringClass().isAssignableFrom(
088: method2.getDeclaringClass()))
089: return false;
090: if (!method2.getName().equals(method1.getName()))
091: return false;
092: if (method1.getDeclaringClass().isInterface())
093: return false;
094: return Arrays.equals(method1.getParameterTypes(), method2
095: .getParameterTypes());
096: }
097:
098: /**
099: * Returns all methods in <code>methods</code> that are overridden in
100: * the specified class hierarchy. The returned <code>Set</code> contains
101: * all overridden methods and all overriding methods.
102: * @param clazz the class hierarchy
103: * @param methods the <code>Set</code> of methods
104: * @return all overridden and overriding methods.
105: */
106: public static Set getOverriddenMethods(Class clazz, Method[] methods) {
107: Method[][] declaredMethods = MethodUtil
108: .getMethodsSortedByInheritanceHierarchy(clazz);
109: Set overridingMethods = new HashSet();
110: for (int ii = 0; ii < methods.length; ii++) {
111: Method currentAroundInvokeMethod = methods[ii];
112: Set currentOverridingMethods = new HashSet();
113: for (int yy = 0; yy < declaredMethods.length; yy++) {
114: for (int zz = 0; zz < declaredMethods[yy].length; zz++) {
115: if (MethodUtil.overrides(currentAroundInvokeMethod,
116: declaredMethods[yy][zz])) {
117: currentOverridingMethods
118: .add(declaredMethods[yy][zz]);
119: }
120: }
121: }
122: if (!currentOverridingMethods.isEmpty()) {
123: overridingMethods.add(currentAroundInvokeMethod);
124: overridingMethods.addAll(currentOverridingMethods);
125: }
126: }
127: return overridingMethods;
128: }
129:
130: /**
131: * Returns the declared methods of the specified class whose names are matching
132: * the specified regular expression.
133: * @param theClass the class whose methods are examined
134: * @param expr the regular expression
135: * @return the matching methods
136: */
137: public static Method[] getMatchingDeclaredMethods(Class theClass,
138: String expr) {
139: Method[] methods = theClass.getDeclaredMethods();
140: List resultList = new ArrayList();
141: for (int ii = 0; ii < methods.length; ii++) {
142: if (StringUtil.matchesPerl5(methods[ii].getName(), expr,
143: true)) {
144: resultList.add(methods[ii]);
145: }
146: }
147: return (Method[]) resultList.toArray(new Method[resultList
148: .size()]);
149: }
150:
151: /**
152: * Returns all non-static methods declared by the specified class and its
153: * superclasses. The returned array contains the methods of all classes
154: * in the inheritance hierarchy, starting with the methods of the
155: * most general superclass, which is <code>java.lang.Object</code>.
156: * @param theClass the class whose methods are examined
157: * @return the array of method arrays
158: */
159: public static Method[][] getMethodsSortedByInheritanceHierarchy(
160: Class theClass) {
161: List hierarchyList = new ArrayList();
162: Class[] hierarchyClasses = ClassUtil
163: .getInheritanceHierarchy(theClass);
164: for (int ii = 0; ii < hierarchyClasses.length; ii++) {
165: addMethodsForClass(hierarchyList, hierarchyClasses[ii]);
166: }
167: return (Method[][]) hierarchyList
168: .toArray(new Method[hierarchyList.size()][]);
169: }
170:
171: private static void addMethodsForClass(List hierarchyList,
172: Class clazz) {
173: List methodList = new ArrayList();
174: Method[] methods = clazz.getDeclaredMethods();
175: for (int ii = 0; ii < methods.length; ii++) {
176: if (!Modifier.isStatic(methods[ii].getModifiers())) {
177: methodList.add(methods[ii]);
178: }
179: }
180: hierarchyList.add(methodList.toArray(new Method[methodList
181: .size()]));
182: }
183: }
|