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 }