1 16 17 package org.apache.commons.jexl.util.introspection; 18 19 import java.lang.reflect.Method ; 20 import java.lang.reflect.Modifier ; 21 import java.util.Hashtable ; 22 import java.util.Map ; 23 24 38 public class ClassMap { 39 40 private static final class CacheMiss { 41 } 42 43 44 private static final CacheMiss CACHE_MISS = new CacheMiss(); 45 46 47 private static final Object OBJECT = new Object (); 48 49 53 54 private Class clazz; 55 56 60 private final Map methodCache = new Hashtable (); 61 62 63 private final MethodMap methodMap = new MethodMap(); 64 65 69 public ClassMap(Class aClass) { 70 clazz = aClass; 71 populateMethodCache(); 72 } 73 74 77 Class getCachedClass() { 78 return clazz; 79 } 80 81 96 public Method findMethod(String name, Object [] params) throws MethodMap.AmbiguousException { 97 String methodKey = makeMethodKey(name, params); 98 Object cacheEntry = methodCache.get(methodKey); 99 100 if (cacheEntry == CACHE_MISS) { 101 return null; 102 } 103 104 if (cacheEntry == null) { 105 try { 106 cacheEntry = methodMap.find(name, params); 107 } catch (MethodMap.AmbiguousException ae) { 108 111 112 methodCache.put(methodKey, CACHE_MISS); 113 114 throw ae; 115 } 116 117 if (cacheEntry == null) { 118 methodCache.put(methodKey, CACHE_MISS); 119 } else { 120 methodCache.put(methodKey, cacheEntry); 121 } 122 } 123 124 126 return (Method ) cacheEntry; 127 } 128 129 133 private void populateMethodCache() { 134 135 138 139 Method [] methods = getAccessibleMethods(clazz); 140 141 144 145 for (int i = 0; i < methods.length; i++) { 146 Method method = methods[i]; 147 148 153 154 Method publicMethod = getPublicMethod(method); 155 156 162 163 if (publicMethod != null) { 164 methodMap.add(publicMethod); 165 methodCache.put(makeMethodKey(publicMethod), publicMethod); 166 } 167 } 168 } 169 170 174 private String makeMethodKey(Method method) { 175 Class [] parameterTypes = method.getParameterTypes(); 176 177 StringBuffer methodKey = new StringBuffer (method.getName()); 178 179 for (int j = 0; j < parameterTypes.length; j++) { 180 186 if (parameterTypes[j].isPrimitive()) { 187 if (parameterTypes[j].equals(Boolean.TYPE)) 188 methodKey.append("java.lang.Boolean"); 189 else if (parameterTypes[j].equals(Byte.TYPE)) 190 methodKey.append("java.lang.Byte"); 191 else if (parameterTypes[j].equals(Character.TYPE)) 192 methodKey.append("java.lang.Character"); 193 else if (parameterTypes[j].equals(Double.TYPE)) 194 methodKey.append("java.lang.Double"); 195 else if (parameterTypes[j].equals(Float.TYPE)) 196 methodKey.append("java.lang.Float"); 197 else if (parameterTypes[j].equals(Integer.TYPE)) 198 methodKey.append("java.lang.Integer"); 199 else if (parameterTypes[j].equals(Long.TYPE)) 200 methodKey.append("java.lang.Long"); 201 else if (parameterTypes[j].equals(Short.TYPE)) 202 methodKey.append("java.lang.Short"); 203 } else { 204 methodKey.append(parameterTypes[j].getName()); 205 } 206 } 207 208 return methodKey.toString(); 209 } 210 211 private static String makeMethodKey(String method, Object [] params) { 212 StringBuffer methodKey = new StringBuffer ().append(method); 213 214 for (int j = 0; j < params.length; j++) { 215 Object arg = params[j]; 216 217 if (arg == null) { 218 arg = OBJECT; 219 } 220 221 methodKey.append(arg.getClass().getName()); 222 } 223 224 return methodKey.toString(); 225 } 226 227 233 private static Method [] getAccessibleMethods(Class clazz) { 234 Method [] methods = clazz.getMethods(); 235 236 240 241 if (Modifier.isPublic(clazz.getModifiers())) { 242 return methods; 243 } 244 245 248 249 MethodInfo[] methodInfos = new MethodInfo[methods.length]; 250 251 for (int i = methods.length; i-- > 0;) { 252 methodInfos[i] = new MethodInfo(methods[i]); 253 } 254 255 int upcastCount = getAccessibleMethods(clazz, methodInfos, 0); 256 257 260 261 if (upcastCount < methods.length) { 262 methods = new Method [upcastCount]; 263 } 264 265 int j = 0; 266 for (int i = 0; i < methodInfos.length; ++i) { 267 MethodInfo methodInfo = methodInfos[i]; 268 if (methodInfo.upcast) { 269 methods[j++] = methodInfo.method; 270 } 271 } 272 return methods; 273 } 274 275 284 private static int getAccessibleMethods(Class clazz, MethodInfo[] methodInfos, int upcastCount) { 285 int l = methodInfos.length; 286 287 291 292 if (Modifier.isPublic(clazz.getModifiers())) { 293 for (int i = 0; i < l && upcastCount < l; ++i) { 294 try { 295 MethodInfo methodInfo = methodInfos[i]; 296 297 if (!methodInfo.upcast) { 298 methodInfo.tryUpcasting(clazz); 299 upcastCount++; 300 } 301 } catch (NoSuchMethodException e) { 302 306 } 307 } 308 309 312 313 if (upcastCount == l) { 314 return upcastCount; 315 } 316 } 317 318 321 322 Class superclazz = clazz.getSuperclass(); 323 324 if (superclazz != null) { 325 upcastCount = getAccessibleMethods(superclazz, methodInfos, upcastCount); 326 327 330 331 if (upcastCount == l) { 332 return upcastCount; 333 } 334 } 335 336 341 342 Class [] interfaces = clazz.getInterfaces(); 343 344 for (int i = interfaces.length; i-- > 0;) { 345 upcastCount = getAccessibleMethods(interfaces[i], methodInfos, upcastCount); 346 347 350 351 if (upcastCount == l) { 352 return upcastCount; 353 } 354 } 355 356 return upcastCount; 357 } 358 359 370 public static Method getPublicMethod(Method method) { 371 Class clazz = method.getDeclaringClass(); 372 373 377 378 if ((clazz.getModifiers() & Modifier.PUBLIC) != 0) { 379 return method; 380 } 381 382 return getPublicMethod(clazz, method.getName(), method.getParameterTypes()); 383 } 384 385 393 private static Method getPublicMethod(Class clazz, String name, Class [] paramTypes) { 394 397 398 if ((clazz.getModifiers() & Modifier.PUBLIC) != 0) { 399 try { 400 return clazz.getMethod(name, paramTypes); 401 } catch (NoSuchMethodException e) { 402 407 return null; 408 } 409 } 410 411 414 415 Class superclazz = clazz.getSuperclass(); 416 417 if (superclazz != null) { 418 Method superclazzMethod = getPublicMethod(superclazz, name, paramTypes); 419 420 if (superclazzMethod != null) { 421 return superclazzMethod; 422 } 423 } 424 425 428 429 Class [] interfaces = clazz.getInterfaces(); 430 431 for (int i = 0; i < interfaces.length; ++i) { 432 Method interfaceMethod = getPublicMethod(interfaces[i], name, paramTypes); 433 434 if (interfaceMethod != null) { 435 return interfaceMethod; 436 } 437 } 438 439 return null; 440 } 441 442 445 private static final class MethodInfo { 446 Method method; 447 448 String name; 449 450 Class [] parameterTypes; 451 452 boolean upcast; 453 454 MethodInfo(Method method) { 455 this.method = null; 456 name = method.getName(); 457 parameterTypes = method.getParameterTypes(); 458 upcast = false; 459 } 460 461 void tryUpcasting(Class clazz) throws NoSuchMethodException { 462 method = clazz.getMethod(name, parameterTypes); 463 name = null; 464 parameterTypes = null; 465 upcast = true; 466 } 467 } 468 } 469 | Popular Tags |