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