1 16 17 package org.apache.commons.jexl.util.introspection; 18 19 import java.lang.reflect.Method ; 20 import java.util.ArrayList ; 21 import java.util.Hashtable ; 22 import java.util.Iterator ; 23 import java.util.LinkedList ; 24 import java.util.List ; 25 import java.util.Map ; 26 27 37 public class MethodMap { 38 39 private static final int MORE_SPECIFIC = 0; 40 41 private static final int LESS_SPECIFIC = 1; 42 43 private static final int INCOMPARABLE = 2; 44 45 48 protected Map methodByNameMap = new Hashtable (); 49 50 55 public void add(Method method) { 56 String methodName = method.getName(); 57 58 List l = get(methodName); 59 60 if (l == null) { 61 l = new ArrayList (); 62 methodByNameMap.put(methodName, l); 63 } 64 65 l.add(method); 66 } 67 68 74 public List get(String key) { 75 return (List ) methodByNameMap.get(key); 76 } 77 78 101 public Method find(String methodName, Object [] args) throws AmbiguousException { 102 List methodList = get(methodName); 103 104 if (methodList == null) { 105 return null; 106 } 107 108 int l = args.length; 109 Class [] classes = new Class [l]; 110 111 for (int i = 0; i < l; ++i) { 112 Object arg = args[i]; 113 114 118 classes[i] = arg == null ? null : arg.getClass(); 119 } 120 121 return getMostSpecific(methodList, classes); 122 } 123 124 128 public static class AmbiguousException extends Exception { 129 130 static final long serialVersionUID = 8758118091728717367L; 131 } 132 133 140 private static Method getMostSpecific(List methods, Class [] classes) throws AmbiguousException { 141 LinkedList applicables = getApplicables(methods, classes); 142 143 if (applicables.isEmpty()) { 144 return null; 145 } 146 147 if (applicables.size() == 1) { 148 return (Method ) applicables.getFirst(); 149 } 150 151 156 157 LinkedList maximals = new LinkedList (); 158 159 for (Iterator applicable = applicables.iterator(); applicable.hasNext();) { 160 Method app = (Method ) applicable.next(); 161 Class [] appArgs = app.getParameterTypes(); 162 boolean lessSpecific = false; 163 164 for (Iterator maximal = maximals.iterator(); !lessSpecific && maximal.hasNext();) { 165 Method max = (Method ) maximal.next(); 166 167 switch (moreSpecific(appArgs, max.getParameterTypes())) { 168 case MORE_SPECIFIC: 169 173 maximal.remove(); 174 break; 175 176 case LESS_SPECIFIC: 177 183 lessSpecific = true; 184 break; 185 } 186 } 187 188 if (!lessSpecific) { 189 maximals.addLast(app); 190 } 191 } 192 193 if (maximals.size() > 1) { 194 throw new AmbiguousException(); 196 } 197 198 return (Method ) maximals.getFirst(); 199 } 200 201 210 private static int moreSpecific(Class [] c1, Class [] c2) { 211 boolean c1MoreSpecific = false; 212 boolean c2MoreSpecific = false; 213 214 for (int i = 0; i < c1.length; ++i) { 215 if (c1[i] != c2[i]) { 216 c1MoreSpecific = c1MoreSpecific || isStrictMethodInvocationConvertible(c2[i], c1[i]); 217 c2MoreSpecific = c2MoreSpecific || isStrictMethodInvocationConvertible(c1[i], c2[i]); 218 } 219 } 220 221 if (c1MoreSpecific) { 222 if (c2MoreSpecific) { 223 227 228 return INCOMPARABLE; 229 } 230 231 return MORE_SPECIFIC; 232 } 233 234 if (c2MoreSpecific) { 235 return LESS_SPECIFIC; 236 } 237 238 242 243 return INCOMPARABLE; 244 } 245 246 255 private static LinkedList getApplicables(List methods, Class [] classes) { 256 LinkedList list = new LinkedList (); 257 258 for (Iterator imethod = methods.iterator(); imethod.hasNext();) { 259 Method method = (Method ) imethod.next(); 260 261 if (isApplicable(method, classes)) { 262 list.add(method); 263 } 264 265 } 266 return list; 267 } 268 269 276 private static boolean isApplicable(Method method, Class [] classes) { 277 Class [] methodArgs = method.getParameterTypes(); 278 279 if (methodArgs.length != classes.length) { 280 return false; 281 } 282 283 for (int i = 0; i < classes.length; ++i) { 284 if (!isMethodInvocationConvertible(methodArgs[i], classes[i])) { 285 return false; 286 } 287 } 288 289 return true; 290 } 291 292 309 private static boolean isMethodInvocationConvertible(Class formal, Class actual) { 310 313 if (actual == null && !formal.isPrimitive()) { 314 return true; 315 } 316 317 320 321 if (actual != null && formal.isAssignableFrom(actual)) { 322 return true; 323 } 324 325 329 330 if (formal.isPrimitive()) { 331 if (formal == Boolean.TYPE && actual == Boolean .class) { 332 return true; 333 } 334 if (formal == Character.TYPE && actual == Character .class) { 335 return true; 336 } 337 if (formal == Byte.TYPE && actual == Byte .class) { 338 return true; 339 } 340 if (formal == Short.TYPE && (actual == Short .class || actual == Byte .class)) { 341 return true; 342 } 343 if (formal == Integer.TYPE && (actual == Integer .class || actual == Short .class || actual == Byte .class)) { 344 return true; 345 } 346 if (formal == Long.TYPE 347 && (actual == Long .class || actual == Integer .class || actual == Short .class || actual == Byte .class)) { 348 return true; 349 } 350 if (formal == Float.TYPE 351 && (actual == Float .class || actual == Long .class || actual == Integer .class 352 || actual == Short .class || actual == Byte .class)) { 353 return true; 354 } 355 if (formal == Double.TYPE 356 && (actual == Double .class || actual == Float .class || actual == Long .class || actual == Integer .class 357 || actual == Short .class || actual == Byte .class)) { 358 return true; 359 } 360 } 361 362 return false; 363 } 364 365 379 private static boolean isStrictMethodInvocationConvertible(Class formal, Class actual) { 380 383 if (actual == null && !formal.isPrimitive()) { 384 return true; 385 } 386 387 390 391 if (formal.isAssignableFrom(actual)) { 392 return true; 393 } 394 395 398 399 if (formal.isPrimitive()) { 400 if (formal == Short.TYPE && (actual == Byte.TYPE)) { 401 return true; 402 } 403 if (formal == Integer.TYPE && (actual == Short.TYPE || actual == Byte.TYPE)) { 404 return true; 405 } 406 if (formal == Long.TYPE && (actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) { 407 return true; 408 } 409 if (formal == Float.TYPE 410 && (actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) { 411 return true; 412 } 413 if (formal == Double.TYPE 414 && (actual == Float.TYPE || actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE 415 || actual == Byte.TYPE)) { 416 return true; 417 } 418 } 419 return false; 420 } 421 } 422 | Popular Tags |