1 16 17 package org.apache.commons.beanutils; 18 19 20 import java.lang.reflect.InvocationTargetException ; 21 import java.lang.reflect.Method ; 22 import java.lang.reflect.Modifier ; 23 24 import java.util.WeakHashMap ; 25 26 import org.apache.commons.logging.Log; 27 import org.apache.commons.logging.LogFactory; 28 29 30 31 54 55 public class MethodUtils { 56 57 59 62 private static Log log = LogFactory.getLog(MethodUtils.class); 63 64 private static boolean loggedAccessibleWarning = false; 65 66 67 private static final Class [] emptyClassArray = new Class [0]; 68 69 private static final Object [] emptyObjectArray = new Object [0]; 70 71 74 private static WeakHashMap cache = new WeakHashMap (); 75 76 78 104 public static Object invokeMethod( 105 Object object, 106 String methodName, 107 Object arg) 108 throws 109 NoSuchMethodException , 110 IllegalAccessException , 111 InvocationTargetException { 112 113 Object [] args = {arg}; 114 return invokeMethod(object, methodName, args); 115 116 } 117 118 119 145 public static Object invokeMethod( 146 Object object, 147 String methodName, 148 Object [] args) 149 throws 150 NoSuchMethodException , 151 IllegalAccessException , 152 InvocationTargetException { 153 154 if (args == null) { 155 args = emptyObjectArray; 156 } 157 int arguments = args.length; 158 Class parameterTypes [] = new Class [arguments]; 159 for (int i = 0; i < arguments; i++) { 160 parameterTypes[i] = args[i].getClass(); 161 } 162 return invokeMethod(object, methodName, args, parameterTypes); 163 164 } 165 166 167 192 public static Object invokeMethod( 193 Object object, 194 String methodName, 195 Object [] args, 196 Class [] parameterTypes) 197 throws 198 NoSuchMethodException , 199 IllegalAccessException , 200 InvocationTargetException { 201 202 if (parameterTypes == null) { 203 parameterTypes = emptyClassArray; 204 } 205 if (args == null) { 206 args = emptyObjectArray; 207 } 208 209 Method method = getMatchingAccessibleMethod( 210 object.getClass(), 211 methodName, 212 parameterTypes); 213 if (method == null) 214 throw new NoSuchMethodException ("No such accessible method: " + 215 methodName + "() on object: " + object.getClass().getName()); 216 return method.invoke(object, args); 217 } 218 219 220 238 public static Object invokeExactMethod( 239 Object object, 240 String methodName, 241 Object arg) 242 throws 243 NoSuchMethodException , 244 IllegalAccessException , 245 InvocationTargetException { 246 247 Object [] args = {arg}; 248 return invokeExactMethod(object, methodName, args); 249 250 } 251 252 253 270 public static Object invokeExactMethod( 271 Object object, 272 String methodName, 273 Object [] args) 274 throws 275 NoSuchMethodException , 276 IllegalAccessException , 277 InvocationTargetException { 278 if (args == null) { 279 args = emptyObjectArray; 280 } 281 int arguments = args.length; 282 Class parameterTypes [] = new Class [arguments]; 283 for (int i = 0; i < arguments; i++) { 284 parameterTypes[i] = args[i].getClass(); 285 } 286 return invokeExactMethod(object, methodName, args, parameterTypes); 287 288 } 289 290 291 309 public static Object invokeExactMethod( 310 Object object, 311 String methodName, 312 Object [] args, 313 Class [] parameterTypes) 314 throws 315 NoSuchMethodException , 316 IllegalAccessException , 317 InvocationTargetException { 318 319 if (args == null) { 320 args = emptyObjectArray; 321 } 322 323 if (parameterTypes == null) { 324 parameterTypes = emptyClassArray; 325 } 326 327 Method method = getAccessibleMethod( 328 object.getClass(), 329 methodName, 330 parameterTypes); 331 if (method == null) 332 throw new NoSuchMethodException ("No such accessible method: " + 333 methodName + "() on object: " + object.getClass().getName()); 334 return method.invoke(object, args); 335 336 } 337 338 339 350 public static Method getAccessibleMethod( 351 Class clazz, 352 String methodName, 353 Class parameterType) { 354 355 Class [] parameterTypes = {parameterType}; 356 return getAccessibleMethod(clazz, methodName, parameterTypes); 357 358 } 359 360 361 372 public static Method getAccessibleMethod( 373 Class clazz, 374 String methodName, 375 Class [] parameterTypes) { 376 377 try { 378 MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, true); 379 Method method = (Method )cache.get(md); 381 if (method != null) { 382 return method; 383 } 384 385 method = getAccessibleMethod 386 (clazz.getMethod(methodName, parameterTypes)); 387 cache.put(md, method); 388 return method; 389 } catch (NoSuchMethodException e) { 390 return (null); 391 } 392 393 } 394 395 396 403 public static Method getAccessibleMethod(Method method) { 404 405 if (method == null) { 407 return (null); 408 } 409 410 if (!Modifier.isPublic(method.getModifiers())) { 412 return (null); 413 } 414 415 Class clazz = method.getDeclaringClass(); 417 if (Modifier.isPublic(clazz.getModifiers())) { 418 return (method); 419 } 420 421 method = 423 getAccessibleMethodFromInterfaceNest(clazz, 424 method.getName(), 425 method.getParameterTypes()); 426 return (method); 427 428 } 429 430 431 433 447 private static Method getAccessibleMethodFromInterfaceNest 448 (Class clazz, String methodName, Class parameterTypes[]) { 449 450 Method method = null; 451 452 for (; clazz != null; clazz = clazz.getSuperclass()) { 454 455 Class interfaces[] = clazz.getInterfaces(); 457 for (int i = 0; i < interfaces.length; i++) { 458 459 if (!Modifier.isPublic(interfaces[i].getModifiers())) 461 continue; 462 463 try { 465 method = interfaces[i].getDeclaredMethod(methodName, 466 parameterTypes); 467 } catch (NoSuchMethodException e) { 468 ; 469 } 470 if (method != null) 471 break; 472 473 method = 475 getAccessibleMethodFromInterfaceNest(interfaces[i], 476 methodName, 477 parameterTypes); 478 if (method != null) 479 break; 480 481 } 482 483 } 484 485 if (method != null) 487 return (method); 488 489 return (null); 491 492 } 493 494 516 public static Method getMatchingAccessibleMethod( 517 Class clazz, 518 String methodName, 519 Class [] parameterTypes) { 520 if (log.isTraceEnabled()) { 522 log.trace("Matching name=" + methodName + " on " + clazz); 523 } 524 MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, false); 525 526 try { 529 Method method = (Method )cache.get(md); 531 if (method != null) { 532 return method; 533 } 534 535 method = clazz.getMethod(methodName, parameterTypes); 536 if (log.isTraceEnabled()) { 537 log.trace("Found straight match: " + method); 538 log.trace("isPublic:" + Modifier.isPublic(method.getModifiers())); 539 } 540 541 try { 542 method.setAccessible(true); 559 560 } catch (SecurityException se) { 561 if (!loggedAccessibleWarning) { 563 boolean vunerableJVM = false; 564 try { 565 String specVersion = System.getProperty("java.specification.version"); 566 if (specVersion.charAt(0) == '1' && 567 (specVersion.charAt(0) == '0' || 568 specVersion.charAt(0) == '1' || 569 specVersion.charAt(0) == '2' || 570 specVersion.charAt(0) == '3')) { 571 572 vunerableJVM = true; 573 } 574 } catch (SecurityException e) { 575 vunerableJVM = true; 577 } 578 if (vunerableJVM) { 579 log.warn( 580 "Current Security Manager restricts use of workarounds for reflection bugs " 581 + " in pre-1.4 JVMs."); 582 } 583 loggedAccessibleWarning = true; 584 } 585 log.debug( 586 "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.", 587 se); 588 } 589 cache.put(md, method); 590 return method; 591 592 } catch (NoSuchMethodException e) { } 593 594 int paramSize = parameterTypes.length; 596 Method [] methods = clazz.getMethods(); 597 for (int i = 0, size = methods.length; i < size ; i++) { 598 if (methods[i].getName().equals(methodName)) { 599 if (log.isTraceEnabled()) { 601 log.trace("Found matching name:"); 602 log.trace(methods[i]); 603 } 604 605 Class [] methodsParams = methods[i].getParameterTypes(); 607 int methodParamSize = methodsParams.length; 608 if (methodParamSize == paramSize) { 609 boolean match = true; 610 for (int n = 0 ; n < methodParamSize; n++) { 611 if (log.isTraceEnabled()) { 612 log.trace("Param=" + parameterTypes[n].getName()); 613 log.trace("Method=" + methodsParams[n].getName()); 614 } 615 if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) { 616 if (log.isTraceEnabled()) { 617 log.trace(methodsParams[n] + " is not assignable from " 618 + parameterTypes[n]); 619 } 620 match = false; 621 break; 622 } 623 } 624 625 if (match) { 626 Method method = getAccessibleMethod(methods[i]); 628 if (method != null) { 629 if (log.isTraceEnabled()) { 630 log.trace(method + " accessible version of " 631 + methods[i]); 632 } 633 try { 634 method.setAccessible(true); 639 640 } catch (SecurityException se) { 641 if (!loggedAccessibleWarning) { 643 log.warn( 644 "Cannot use JVM pre-1.4 access bug workaround due to restrictive security manager."); 645 loggedAccessibleWarning = true; 646 } 647 log.debug( 648 "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.", 649 se); 650 } 651 cache.put(md, method); 652 return method; 653 } 654 655 log.trace("Couldn't find accessible method."); 656 } 657 } 658 } 659 } 660 661 log.trace("No match found."); 663 return null; 664 } 665 666 683 public static final boolean isAssignmentCompatible(Class parameterType, Class parameterization) { 684 if (parameterType.isAssignableFrom(parameterization)) { 686 return true; 687 } 688 689 if (parameterType.isPrimitive()) { 690 Class parameterWrapperClazz = getPrimitiveWrapper(parameterType); 693 if (parameterWrapperClazz != null) { 694 return parameterWrapperClazz.equals(parameterization); 695 } 696 } 697 698 return false; 699 } 700 701 708 public static Class getPrimitiveWrapper(Class primitiveType) { 709 if (boolean.class.equals(primitiveType)) { 711 return Boolean .class; 712 } else if (float.class.equals(primitiveType)) { 713 return Float .class; 714 } else if (long.class.equals(primitiveType)) { 715 return Long .class; 716 } else if (int.class.equals(primitiveType)) { 717 return Integer .class; 718 } else if (short.class.equals(primitiveType)) { 719 return Short .class; 720 } else if (byte.class.equals(primitiveType)) { 721 return Byte .class; 722 } else if (double.class.equals(primitiveType)) { 723 return Double .class; 724 } else if (char.class.equals(primitiveType)) { 725 return Character .class; 726 } else { 727 728 return null; 729 } 730 } 731 732 739 public static Class getPrimitiveType(Class wrapperType) { 740 if (Boolean .class.equals(wrapperType)) { 742 return boolean.class; 743 } else if (Float .class.equals(wrapperType)) { 744 return float.class; 745 } else if (Long .class.equals(wrapperType)) { 746 return long.class; 747 } else if (Integer .class.equals(wrapperType)) { 748 return int.class; 749 } else if (Short .class.equals(wrapperType)) { 750 return short.class; 751 } else if (Byte .class.equals(wrapperType)) { 752 return byte.class; 753 } else if (Double .class.equals(wrapperType)) { 754 return double.class; 755 } else if (Character .class.equals(wrapperType)) { 756 return char.class; 757 } else { 758 if (log.isDebugEnabled()) { 759 log.debug("Not a known primitive wrapper class: " + wrapperType); 760 } 761 return null; 762 } 763 } 764 765 771 public static Class toNonPrimitiveClass(Class clazz) { 772 if (clazz.isPrimitive()) { 773 Class primitiveClazz = MethodUtils.getPrimitiveWrapper(clazz); 774 if (primitiveClazz != null) { 776 return primitiveClazz; 777 } else { 778 return clazz; 779 } 780 } else { 781 return clazz; 782 } 783 } 784 785 786 789 private static class MethodDescriptor { 790 private Class cls; 791 private String methodName; 792 private Class [] paramTypes; 793 private boolean exact; 794 private int hashCode; 795 796 804 public MethodDescriptor(Class cls, String methodName, Class [] paramTypes, boolean exact) { 805 if (cls == null) { 806 throw new IllegalArgumentException ("Class cannot be null"); 807 } 808 if (methodName == null) { 809 throw new IllegalArgumentException ("Method Name cannot be null"); 810 } 811 if (paramTypes == null) { 812 paramTypes = emptyClassArray; 813 } 814 815 this.cls = cls; 816 this.methodName = methodName; 817 this.paramTypes = paramTypes; 818 this.exact= exact; 819 820 this.hashCode = methodName.length(); 821 } 822 827 public boolean equals(Object obj) { 828 if (!(obj instanceof MethodDescriptor)) { 829 return false; 830 } 831 MethodDescriptor md = (MethodDescriptor)obj; 832 833 return ( 834 exact == md.exact && 835 methodName.equals(md.methodName) && 836 cls.equals(md.cls) && 837 java.util.Arrays.equals(paramTypes, md.paramTypes) 838 ); 839 } 840 847 public int hashCode() { 848 return hashCode; 849 } 850 } 851 } 852 | Popular Tags |