1 package org.apache.velocity.util.introspection; 2 3 18 19 import java.util.Iterator ; 20 import java.util.List ; 21 import java.util.ArrayList ; 22 import java.util.LinkedList ; 23 import java.util.Set ; 24 import java.util.HashSet ; 25 import java.util.Map ; 26 import java.util.Hashtable ; 27 28 import java.lang.reflect.Method ; 29 30 39 public class MethodMap 40 { 41 private static final int MORE_SPECIFIC = 0; 42 private static final int LESS_SPECIFIC = 1; 43 private static final int INCOMPARABLE = 2; 44 45 48 Map methodByNameMap = new Hashtable (); 49 50 55 public void add(Method method) 56 { 57 String methodName = method.getName(); 58 59 List l = get( methodName ); 60 61 if ( l == null) 62 { 63 l = new ArrayList (); 64 methodByNameMap.put(methodName, l); 65 } 66 67 l.add(method); 68 69 return; 70 } 71 72 78 public List get(String key) 79 { 80 return (List ) methodByNameMap.get(key); 81 } 82 83 111 public Method find(String methodName, Object [] args) 112 throws AmbiguousException 113 { 114 List methodList = get(methodName); 115 116 if (methodList == null) 117 { 118 return null; 119 } 120 121 int l = args.length; 122 Class [] classes = new Class [l]; 123 124 for(int i = 0; i < l; ++i) 125 { 126 Object arg = args[i]; 127 128 132 classes[i] = 133 arg == null ? null : arg.getClass(); 134 } 135 136 return getMostSpecific(methodList, classes); 137 } 138 139 143 public static class AmbiguousException extends Exception 144 { 145 } 146 147 148 private static Method getMostSpecific(List methods, Class [] classes) 149 throws AmbiguousException 150 { 151 LinkedList applicables = getApplicables(methods, classes); 152 153 if(applicables.isEmpty()) 154 { 155 return null; 156 } 157 158 if(applicables.size() == 1) 159 { 160 return (Method )applicables.getFirst(); 161 } 162 163 168 169 LinkedList maximals = new LinkedList (); 170 171 for (Iterator applicable = applicables.iterator(); 172 applicable.hasNext();) 173 { 174 Method app = (Method ) applicable.next(); 175 Class [] appArgs = app.getParameterTypes(); 176 boolean lessSpecific = false; 177 178 for (Iterator maximal = maximals.iterator(); 179 !lessSpecific && maximal.hasNext();) 180 { 181 Method max = (Method ) maximal.next(); 182 183 switch(moreSpecific(appArgs, max.getParameterTypes())) 184 { 185 case MORE_SPECIFIC: 186 { 187 191 192 maximal.remove(); 193 break; 194 } 195 196 case LESS_SPECIFIC: 197 { 198 204 205 lessSpecific = true; 206 break; 207 } 208 } 209 } 210 211 if(!lessSpecific) 212 { 213 maximals.addLast(app); 214 } 215 } 216 217 if(maximals.size() > 1) 218 { 219 throw new AmbiguousException(); 221 } 222 223 return (Method )maximals.getFirst(); 224 } 225 226 234 private static int moreSpecific(Class [] c1, Class [] c2) 235 { 236 boolean c1MoreSpecific = false; 237 boolean c2MoreSpecific = false; 238 239 for(int i = 0; i < c1.length; ++i) 240 { 241 if(c1[i] != c2[i]) 242 { 243 c1MoreSpecific = 244 c1MoreSpecific || 245 isStrictMethodInvocationConvertible(c2[i], c1[i]); 246 c2MoreSpecific = 247 c2MoreSpecific || 248 isStrictMethodInvocationConvertible(c1[i], c2[i]); 249 } 250 } 251 252 if(c1MoreSpecific) 253 { 254 if(c2MoreSpecific) 255 { 256 260 261 return INCOMPARABLE; 262 } 263 264 return MORE_SPECIFIC; 265 } 266 267 if(c2MoreSpecific) 268 { 269 return LESS_SPECIFIC; 270 } 271 272 276 277 return INCOMPARABLE; 278 } 279 280 288 private static LinkedList getApplicables(List methods, Class [] classes) 289 { 290 LinkedList list = new LinkedList (); 291 292 for (Iterator imethod = methods.iterator(); imethod.hasNext();) 293 { 294 Method method = (Method ) imethod.next(); 295 296 if(isApplicable(method, classes)) 297 { 298 list.add(method); 299 } 300 301 } 302 return list; 303 } 304 305 309 private static boolean isApplicable(Method method, Class [] classes) 310 { 311 Class [] methodArgs = method.getParameterTypes(); 312 313 if(methodArgs.length != classes.length) 314 { 315 return false; 316 } 317 318 for(int i = 0; i < classes.length; ++i) 319 { 320 if(!isMethodInvocationConvertible(methodArgs[i], classes[i])) 321 { 322 return false; 323 } 324 } 325 326 return true; 327 } 328 329 347 private static boolean isMethodInvocationConvertible(Class formal, 348 Class actual) 349 { 350 353 if (actual == null && !formal.isPrimitive()) 354 { 355 return true; 356 } 357 358 361 362 if (actual != null && formal.isAssignableFrom(actual)) 363 { 364 return true; 365 } 366 367 371 372 if (formal.isPrimitive()) 373 { 374 if(formal == Boolean.TYPE && actual == Boolean .class) 375 return true; 376 if(formal == Character.TYPE && actual == Character .class) 377 return true; 378 if(formal == Byte.TYPE && actual == Byte .class) 379 return true; 380 if(formal == Short.TYPE && 381 (actual == Short .class || actual == Byte .class)) 382 return true; 383 if(formal == Integer.TYPE && 384 (actual == Integer .class || actual == Short .class || 385 actual == Byte .class)) 386 return true; 387 if(formal == Long.TYPE && 388 (actual == Long .class || actual == Integer .class || 389 actual == Short .class || actual == Byte .class)) 390 return true; 391 if(formal == Float.TYPE && 392 (actual == Float .class || actual == Long .class || 393 actual == Integer .class || actual == Short .class || 394 actual == Byte .class)) 395 return true; 396 if(formal == Double.TYPE && 397 (actual == Double .class || actual == Float .class || 398 actual == Long .class || actual == Integer .class || 399 actual == Short .class || actual == Byte .class)) 400 return true; 401 } 402 403 return false; 404 } 405 406 420 private static boolean isStrictMethodInvocationConvertible(Class formal, 421 Class actual) 422 { 423 426 if (actual == null && !formal.isPrimitive()) 427 { 428 return true; 429 } 430 431 434 435 if(formal.isAssignableFrom(actual)) 436 { 437 return true; 438 } 439 440 443 444 if(formal.isPrimitive()) 445 { 446 if(formal == Short.TYPE && (actual == Byte.TYPE)) 447 return true; 448 if(formal == Integer.TYPE && 449 (actual == Short.TYPE || actual == Byte.TYPE)) 450 return true; 451 if(formal == Long.TYPE && 452 (actual == Integer.TYPE || actual == Short.TYPE || 453 actual == Byte.TYPE)) 454 return true; 455 if(formal == Float.TYPE && 456 (actual == Long.TYPE || actual == Integer.TYPE || 457 actual == Short.TYPE || actual == Byte.TYPE)) 458 return true; 459 if(formal == Double.TYPE && 460 (actual == Float.TYPE || actual == Long.TYPE || 461 actual == Integer.TYPE || actual == Short.TYPE || 462 actual == Byte.TYPE)) 463 return true; 464 } 465 return false; 466 } 467 } 468 | Popular Tags |