1 package org.apache.velocity.util.introspection; 2 3 18 19 import java.util.Map ; 20 import java.util.List ; 21 import java.util.Hashtable ; 22 23 import java.lang.reflect.Method ; 24 import java.lang.reflect.Modifier ; 25 26 37 public class ClassMap 38 { 39 private static final class CacheMiss { } 40 private static final CacheMiss CACHE_MISS = new CacheMiss(); 41 private static final Object OBJECT = new Object (); 42 43 47 48 private Class clazz; 49 50 54 private Map methodCache = new Hashtable (); 55 56 private MethodMap methodMap = new MethodMap(); 57 58 61 public ClassMap( Class clazz) 62 { 63 this.clazz = clazz; 64 populateMethodCache(); 65 } 66 67 private ClassMap() 68 { 69 } 70 71 74 Class getCachedClass() 75 { 76 return clazz; 77 } 78 79 91 public Method findMethod(String name, Object [] params) 92 throws MethodMap.AmbiguousException 93 { 94 String methodKey = makeMethodKey(name, params); 95 Object cacheEntry = methodCache.get( methodKey ); 96 97 if (cacheEntry == CACHE_MISS) 98 { 99 return null; 100 } 101 102 if (cacheEntry == null) 103 { 104 try 105 { 106 cacheEntry = methodMap.find( name, 107 params ); 108 } 109 catch( MethodMap.AmbiguousException ae ) 110 { 111 114 115 methodCache.put( methodKey, 116 CACHE_MISS ); 117 118 throw ae; 119 } 120 121 if ( cacheEntry == null ) 122 { 123 methodCache.put( methodKey, 124 CACHE_MISS ); 125 } 126 else 127 { 128 methodCache.put( methodKey, 129 cacheEntry ); 130 } 131 } 132 133 135 return (Method ) cacheEntry; 136 } 137 138 143 private void populateMethodCache() 144 { 145 StringBuffer methodKey; 146 147 150 151 Method [] methods = getAccessibleMethods(clazz); 152 153 156 157 for (int i = 0; i < methods.length; i++) 158 { 159 Method method = methods[i]; 160 161 166 167 Method publicMethod = getPublicMethod( method ); 168 169 175 176 if ( publicMethod != null) 177 { 178 methodMap.add( publicMethod ); 179 methodCache.put( makeMethodKey( publicMethod), publicMethod); 180 } 181 } 182 } 183 184 189 private String makeMethodKey(Method method) 190 { 191 Class [] parameterTypes = method.getParameterTypes(); 192 193 StringBuffer methodKey = new StringBuffer (method.getName()); 194 195 for (int j = 0; j < parameterTypes.length; j++) 196 { 197 203 if (parameterTypes[j].isPrimitive()) 204 { 205 if (parameterTypes[j].equals(Boolean.TYPE)) 206 methodKey.append("java.lang.Boolean"); 207 else if (parameterTypes[j].equals(Byte.TYPE)) 208 methodKey.append("java.lang.Byte"); 209 else if (parameterTypes[j].equals(Character.TYPE)) 210 methodKey.append("java.lang.Character"); 211 else if (parameterTypes[j].equals(Double.TYPE)) 212 methodKey.append("java.lang.Double"); 213 else if (parameterTypes[j].equals(Float.TYPE)) 214 methodKey.append("java.lang.Float"); 215 else if (parameterTypes[j].equals(Integer.TYPE)) 216 methodKey.append("java.lang.Integer"); 217 else if (parameterTypes[j].equals(Long.TYPE)) 218 methodKey.append("java.lang.Long"); 219 else if (parameterTypes[j].equals(Short.TYPE)) 220 methodKey.append("java.lang.Short"); 221 } 222 else 223 { 224 methodKey.append(parameterTypes[j].getName()); 225 } 226 } 227 228 return methodKey.toString(); 229 } 230 231 private static String makeMethodKey(String method, Object [] params) 232 { 233 StringBuffer methodKey = new StringBuffer ().append(method); 234 235 for (int j = 0; j < params.length; j++) 236 { 237 Object arg = params[j]; 238 239 if (arg == null) 240 { 241 arg = OBJECT; 242 } 243 244 methodKey.append(arg.getClass().getName()); 245 } 246 247 return methodKey.toString(); 248 } 249 250 256 private static Method [] getAccessibleMethods(Class clazz) 257 { 258 Method [] methods = clazz.getMethods(); 259 260 264 265 if (Modifier.isPublic(clazz.getModifiers())) 266 { 267 return methods; 268 } 269 270 273 274 MethodInfo[] methodInfos = new MethodInfo[methods.length]; 275 276 for(int i = methods.length; i-- > 0; ) 277 { 278 methodInfos[i] = new MethodInfo(methods[i]); 279 } 280 281 int upcastCount = getAccessibleMethods(clazz, methodInfos, 0); 282 283 286 287 if(upcastCount < methods.length) 288 { 289 methods = new Method [upcastCount]; 290 } 291 292 int j = 0; 293 for(int i = 0; i < methodInfos.length; ++i) 294 { 295 MethodInfo methodInfo = methodInfos[i]; 296 if(methodInfo.upcast) 297 { 298 methods[j++] = methodInfo.method; 299 } 300 } 301 return methods; 302 } 303 304 313 private static int getAccessibleMethods( Class clazz, MethodInfo[] methodInfos, int upcastCount) 314 { 315 int l = methodInfos.length; 316 317 321 322 if( Modifier.isPublic(clazz.getModifiers()) ) 323 { 324 for(int i = 0; i < l && upcastCount < l; ++i) 325 { 326 try 327 { 328 MethodInfo methodInfo = methodInfos[i]; 329 330 if(!methodInfo.upcast) 331 { 332 methodInfo.tryUpcasting(clazz); 333 upcastCount++; 334 } 335 } 336 catch(NoSuchMethodException e) 337 { 338 342 } 343 } 344 345 348 349 if(upcastCount == l) 350 { 351 return upcastCount; 352 } 353 } 354 355 358 359 Class superclazz = clazz.getSuperclass(); 360 361 if(superclazz != null) 362 { 363 upcastCount = getAccessibleMethods(superclazz , methodInfos, upcastCount); 364 365 368 369 if(upcastCount == l) 370 { 371 return upcastCount; 372 } 373 } 374 375 380 381 Class [] interfaces = clazz.getInterfaces(); 382 383 for(int i = interfaces.length; i-- > 0; ) 384 { 385 upcastCount = getAccessibleMethods(interfaces[i], methodInfos, upcastCount); 386 387 390 391 if(upcastCount == l) 392 { 393 return upcastCount; 394 } 395 } 396 397 return upcastCount; 398 } 399 400 411 public static Method getPublicMethod(Method method) 412 { 413 Class clazz = method.getDeclaringClass(); 414 415 419 420 if((clazz.getModifiers() & Modifier.PUBLIC) != 0) 421 { 422 return method; 423 } 424 425 return getPublicMethod(clazz, method.getName(), method.getParameterTypes()); 426 } 427 428 436 private static Method getPublicMethod(Class clazz, String name, Class [] paramTypes) 437 { 438 441 442 if((clazz.getModifiers() & Modifier.PUBLIC) != 0) 443 { 444 try 445 { 446 return clazz.getMethod(name, paramTypes); 447 } 448 catch(NoSuchMethodException e) 449 { 450 455 return null; 456 } 457 } 458 459 462 463 464 Class superclazz = clazz.getSuperclass(); 465 466 if ( superclazz != null ) 467 { 468 Method superclazzMethod = getPublicMethod(superclazz, name, paramTypes); 469 470 if(superclazzMethod != null) 471 { 472 return superclazzMethod; 473 } 474 } 475 476 479 480 Class [] interfaces = clazz.getInterfaces(); 481 482 for(int i = 0; i < interfaces.length; ++i) 483 { 484 Method interfaceMethod = getPublicMethod(interfaces[i], name, paramTypes); 485 486 if(interfaceMethod != null) 487 { 488 return interfaceMethod; 489 } 490 } 491 492 return null; 493 } 494 495 498 private static final class MethodInfo 499 { 500 Method method; 501 String name; 502 Class [] parameterTypes; 503 boolean upcast; 504 505 MethodInfo(Method method) 506 { 507 this.method = null; 508 name = method.getName(); 509 parameterTypes = method.getParameterTypes(); 510 upcast = false; 511 } 512 513 void tryUpcasting(Class clazz) 514 throws NoSuchMethodException 515 { 516 method = clazz.getMethod(name, parameterTypes); 517 name = null; 518 parameterTypes = null; 519 upcast = true; 520 } 521 } 522 } 523 | Popular Tags |