1 16 package org.apache.commons.jxpath.util; 17 18 import java.lang.reflect.Constructor ; 19 import java.lang.reflect.Method ; 20 import java.lang.reflect.Modifier ; 21 import java.util.Arrays ; 22 23 import org.apache.commons.jxpath.ExpressionContext; 24 import org.apache.commons.jxpath.JXPathException; 25 26 33 public class MethodLookupUtils { 34 35 private static final int NO_MATCH = 0; 36 private static final int APPROXIMATE_MATCH = 1; 37 private static final int EXACT_MATCH = 2; 38 private static final Object [] EMPTY_ARRAY = new Object [0]; 39 40 public static Constructor lookupConstructor( 41 Class targetClass, 42 Object [] parameters) 43 { 44 boolean tryExact = true; 45 int count = parameters == null ? 0 : parameters.length; 46 Class types[] = new Class [count]; 47 for (int i = 0; i < count; i++) { 48 Object param = parameters[i]; 49 if (param != null) { 50 types[i] = param.getClass(); 51 } 52 else { 53 types[i] = null; 54 tryExact = false; 55 } 56 } 57 58 Constructor constructor = null; 59 60 if (tryExact) { 61 try { 63 constructor = targetClass.getConstructor(types); 64 if (constructor != null) { 65 return constructor; 66 } 67 } 68 catch (NoSuchMethodException ex) { 69 } 71 } 72 73 int currentMatch = 0; 74 boolean ambiguous = false; 75 76 Constructor [] constructors = targetClass.getConstructors(); 78 for (int i = 0; i < constructors.length; i++) { 79 int match = 80 matchParameterTypes( 81 constructors[i].getParameterTypes(), 82 parameters); 83 if (match != NO_MATCH) { 84 if (match > currentMatch) { 85 constructor = constructors[i]; 86 currentMatch = match; 87 ambiguous = false; 88 } 89 else if (match == currentMatch) { 90 ambiguous = true; 91 } 92 } 93 } 94 if (ambiguous) { 95 throw new JXPathException( 96 "Ambigous constructor " + Arrays.asList(parameters)); 97 } 98 return constructor; 99 } 100 101 public static Method lookupStaticMethod( 102 Class targetClass, 103 String name, 104 Object [] parameters) 105 { 106 boolean tryExact = true; 107 int count = parameters == null ? 0 : parameters.length; 108 Class types[] = new Class [count]; 109 for (int i = 0; i < count; i++) { 110 Object param = parameters[i]; 111 if (param != null) { 112 types[i] = param.getClass(); 113 } 114 else { 115 types[i] = null; 116 tryExact = false; 117 } 118 } 119 120 Method method = null; 121 122 if (tryExact) { 123 try { 125 method = targetClass.getMethod(name, types); 126 if (method != null 127 && Modifier.isStatic(method.getModifiers())) { 128 return method; 129 } 130 } 131 catch (NoSuchMethodException ex) { 132 } 134 } 135 136 int currentMatch = 0; 137 boolean ambiguous = false; 138 139 Method [] methods = targetClass.getMethods(); 141 for (int i = 0; i < methods.length; i++) { 142 if (Modifier.isStatic(methods[i].getModifiers()) 143 && methods[i].getName().equals(name)) { 144 int match = 145 matchParameterTypes( 146 methods[i].getParameterTypes(), 147 parameters); 148 if (match != NO_MATCH) { 149 if (match > currentMatch) { 150 method = methods[i]; 151 currentMatch = match; 152 ambiguous = false; 153 } 154 else if (match == currentMatch) { 155 ambiguous = true; 156 } 157 } 158 } 159 } 160 if (ambiguous) { 161 throw new JXPathException("Ambigous method call: " + name); 162 } 163 return method; 164 } 165 166 public static Method lookupMethod( 167 Class targetClass, 168 String name, 169 Object [] parameters) 170 { 171 if (parameters == null 172 || parameters.length < 1 173 || parameters[0] == null) { 174 return null; 175 } 176 177 if (matchType(targetClass, parameters[0]) == NO_MATCH) { 178 return null; 179 } 180 181 targetClass = TypeUtils.convert(parameters[0], targetClass).getClass(); 182 183 boolean tryExact = true; 184 int count = parameters.length - 1; 185 Class types[] = new Class [count]; 186 Object arguments[] = new Object [count]; 187 for (int i = 0; i < count; i++) { 188 Object param = parameters[i + 1]; 189 arguments[i] = param; 190 if (param != null) { 191 types[i] = param.getClass(); 192 } 193 else { 194 types[i] = null; 195 tryExact = false; 196 } 197 } 198 199 Method method = null; 200 201 if (tryExact) { 202 try { 204 method = targetClass.getMethod(name, types); 205 if (method != null 206 && !Modifier.isStatic(method.getModifiers())) { 207 return method; 208 } 209 } 210 catch (NoSuchMethodException ex) { 211 } 213 } 214 215 int currentMatch = 0; 216 boolean ambiguous = false; 217 218 Method [] methods = targetClass.getMethods(); 220 for (int i = 0; i < methods.length; i++) { 221 if (!Modifier.isStatic(methods[i].getModifiers()) 222 && methods[i].getName().equals(name)) { 223 int match = 224 matchParameterTypes( 225 methods[i].getParameterTypes(), 226 arguments); 227 if (match != NO_MATCH) { 228 if (match > currentMatch) { 229 method = methods[i]; 230 currentMatch = match; 231 ambiguous = false; 232 } 233 else if (match == currentMatch) { 234 ambiguous = true; 235 } 236 } 237 } 238 } 239 if (ambiguous) { 240 throw new JXPathException("Ambigous method call: " + name); 241 } 242 return method; 243 } 244 245 private static int matchParameterTypes( 246 Class types[], 247 Object parameters[]) 248 { 249 int pi = 0; 250 if (types.length >= 1 251 && ExpressionContext.class.isAssignableFrom(types[0])) { 252 pi++; 253 } 254 int length = parameters == null ? 0 : parameters.length; 255 if (types.length != length + pi) { 256 return NO_MATCH; 257 } 258 int totalMatch = EXACT_MATCH; 259 for (int i = 0; i < length; i++) { 260 int match = matchType(types[i + pi], parameters[i]); 261 if (match == NO_MATCH) { 262 return NO_MATCH; 263 } 264 if (match < totalMatch) { 265 totalMatch = match; 266 } 267 } 268 return totalMatch; 269 } 270 271 private static int matchType(Class expected, Object object) { 272 if (object == null) { 273 return APPROXIMATE_MATCH; 274 } 275 276 Class actual = object.getClass(); 277 278 if (expected.equals(actual)) { 279 return EXACT_MATCH; 280 } 281 if (expected.isAssignableFrom(actual)) { 282 return EXACT_MATCH; 283 } 284 285 if (TypeUtils.canConvert(object, expected)) { 286 return APPROXIMATE_MATCH; 287 } 288 289 return NO_MATCH; 290 } 291 } | Popular Tags |