001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.lang.reflect; 018 019 import java.lang.reflect.InvocationTargetException; 020 import java.lang.reflect.Method; 021 import java.lang.reflect.Modifier; 022 023 import org.apache.commons.lang.ArrayUtils; 024 import org.apache.commons.lang.ClassUtils; 025 026 /** 027 * <p> Utility reflection methods focused on methods, originally from Commons BeanUtils. 028 * Differences from the BeanUtils version may be noted, especially where similar functionality 029 * already existed within Lang. 030 * </p> 031 * 032 * <h3>Known Limitations</h3> 033 * <h4>Accessing Public Methods In A Default Access Superclass</h4> 034 * <p>There is an issue when invoking public methods contained in a default access superclass on JREs prior to 1.4. 035 * Reflection locates these methods fine and correctly assigns them as public. 036 * However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p> 037 * 038 * <p><code>MethodUtils</code> contains a workaround for this situation. 039 * It will attempt to call <code>setAccessible</code> on this method. 040 * If this call succeeds, then the method can be invoked as normal. 041 * This call will only succeed when the application has sufficient security privileges. 042 * If this call fails then the method may fail.</p> 043 * 044 * @author Apache Software Foundation 045 * @author Craig R. McClanahan 046 * @author Ralph Schaer 047 * @author Chris Audley 048 * @author Rey François 049 * @author Gregor Raýman 050 * @author Jan Sorensen 051 * @author Robert Burrell Donkin 052 * @author Matt Benson 053 * @since 2.5 054 * @version $Id: MethodUtils.java 911986 2010-02-19 21:19:05Z niallp $ 055 */ 056 public class MethodUtils { 057 058 /** 059 * <p>MethodUtils instances should NOT be constructed in standard programming. 060 * Instead, the class should be used as 061 * <code>MethodUtils.getAccessibleMethod(method)</code>.</p> 062 * 063 * <p>This constructor is public to permit tools that require a JavaBean 064 * instance to operate.</p> 065 */ 066 public MethodUtils() { 067 super(); 068 } 069 070 /** 071 * <p>Invoke a named method whose parameter type matches the object type.</p> 072 * 073 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p> 074 * 075 * <p>This method supports calls to methods taking primitive parameters 076 * via passing in wrapping classes. So, for example, a <code>Boolean</code> object 077 * would match a <code>boolean</code> primitive.</p> 078 * 079 * <p> This is a convenient wrapper for 080 * {@link #invokeMethod(Object object, String methodName, Object[] args)}. 081 * </p> 082 * 083 * @param object invoke method on this object 084 * @param methodName get method with this name 085 * @param arg use this argument 086 * @return The value returned by the invoked method 087 * 088 * @throws NoSuchMethodException if there is no such accessible method 089 * @throws InvocationTargetException wraps an exception thrown by the method invoked 090 * @throws IllegalAccessException if the requested method is not accessible via reflection 091 */ 092 public static Object invokeMethod(Object object, String methodName, 093 Object arg) throws NoSuchMethodException, IllegalAccessException, 094 InvocationTargetException { 095 return invokeMethod(object, methodName, new Object[] { arg }); 096 } 097 098 /** 099 * <p>Invoke a named method whose parameter type matches the object type.</p> 100 * 101 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p> 102 * 103 * <p>This method supports calls to methods taking primitive parameters 104 * via passing in wrapping classes. So, for example, a <code>Boolean</code> object 105 * would match a <code>boolean</code> primitive.</p> 106 * 107 * <p> This is a convenient wrapper for 108 * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. 109 * </p> 110 * 111 * @param object invoke method on this object 112 * @param methodName get method with this name 113 * @param args use these arguments - treat null as empty array 114 * @return The value returned by the invoked method 115 * 116 * @throws NoSuchMethodException if there is no such accessible method 117 * @throws InvocationTargetException wraps an exception thrown by the method invoked 118 * @throws IllegalAccessException if the requested method is not accessible via reflection 119 */ 120 public static Object invokeMethod(Object object, String methodName, 121 Object[] args) throws NoSuchMethodException, 122 IllegalAccessException, InvocationTargetException { 123 if (args == null) { 124 args = ArrayUtils.EMPTY_OBJECT_ARRAY; 125 } 126 int arguments = args.length; 127 Class[] parameterTypes = new Class[arguments]; 128 for (int i = 0; i < arguments; i++) { 129 parameterTypes[i] = args[i].getClass(); 130 } 131 return invokeMethod(object, methodName, args, parameterTypes); 132 } 133 134 /** 135 * <p>Invoke a named method whose parameter type matches the object type.</p> 136 * 137 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p> 138 * 139 * <p>This method supports calls to methods taking primitive parameters 140 * via passing in wrapping classes. So, for example, a <code>Boolean</code> object 141 * would match a <code>boolean</code> primitive.</p> 142 * 143 * @param object invoke method on this object 144 * @param methodName get method with this name 145 * @param args use these arguments - treat null as empty array 146 * @param parameterTypes match these parameters - treat null as empty array 147 * @return The value returned by the invoked method 148 * 149 * @throws NoSuchMethodException if there is no such accessible method 150 * @throws InvocationTargetException wraps an exception thrown by the method invoked 151 * @throws IllegalAccessException if the requested method is not accessible via reflection 152 */ 153 public static Object invokeMethod(Object object, String methodName, 154 Object[] args, Class[] parameterTypes) 155 throws NoSuchMethodException, IllegalAccessException, 156 InvocationTargetException { 157 if (parameterTypes == null) { 158 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY; 159 } 160 if (args == null) { 161 args = ArrayUtils.EMPTY_OBJECT_ARRAY; 162 } 163 Method method = getMatchingAccessibleMethod(object.getClass(), 164 methodName, parameterTypes); 165 if (method == null) { 166 throw new NoSuchMethodException("No such accessible method: " 167 + methodName + "() on object: " 168 + object.getClass().getName()); 169 } 170 return method.invoke(object, args); 171 } 172 173 /** 174 * <p>Invoke a method whose parameter type matches exactly the object 175 * type.</p> 176 * 177 * <p> This is a convenient wrapper for 178 * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}. 179 * </p> 180 * 181 * @param object invoke method on this object 182 * @param methodName get method with this name 183 * @param arg use this argument 184 * @return The value returned by the invoked method 185 * 186 * @throws NoSuchMethodException if there is no such accessible method 187 * @throws InvocationTargetException wraps an exception thrown by the 188 * method invoked 189 * @throws IllegalAccessException if the requested method is not accessible 190 * via reflection 191 */ 192 public static Object invokeExactMethod(Object object, String methodName, 193 Object arg) throws NoSuchMethodException, IllegalAccessException, 194 InvocationTargetException { 195 return invokeExactMethod(object, methodName, new Object[] { arg }); 196 } 197 198 /** 199 * <p>Invoke a method whose parameter types match exactly the object 200 * types.</p> 201 * 202 * <p> This uses reflection to invoke the method obtained from a call to 203 * <code>getAccessibleMethod()</code>.</p> 204 * 205 * @param object invoke method on this object 206 * @param methodName get method with this name 207 * @param args use these arguments - treat null as empty array 208 * @return The value returned by the invoked method 209 * 210 * @throws NoSuchMethodException if there is no such accessible method 211 * @throws InvocationTargetException wraps an exception thrown by the 212 * method invoked 213 * @throws IllegalAccessException if the requested method is not accessible 214 * via reflection 215 */ 216 public static Object invokeExactMethod(Object object, String methodName, 217 Object[] args) throws NoSuchMethodException, 218 IllegalAccessException, InvocationTargetException { 219 if (args == null) { 220 args = ArrayUtils.EMPTY_OBJECT_ARRAY; 221 } 222 int arguments = args.length; 223 Class[] parameterTypes = new Class[arguments]; 224 for (int i = 0; i < arguments; i++) { 225 parameterTypes[i] = args[i].getClass(); 226 } 227 return invokeExactMethod(object, methodName, args, parameterTypes); 228 } 229 230 /** 231 * <p>Invoke a method whose parameter types match exactly the parameter 232 * types given.</p> 233 * 234 * <p>This uses reflection to invoke the method obtained from a call to 235 * <code>getAccessibleMethod()</code>.</p> 236 * 237 * @param object invoke method on this object 238 * @param methodName get method with this name 239 * @param args use these arguments - treat null as empty array 240 * @param parameterTypes match these parameters - treat null as empty array 241 * @return The value returned by the invoked method 242 * 243 * @throws NoSuchMethodException if there is no such accessible method 244 * @throws InvocationTargetException wraps an exception thrown by the 245 * method invoked 246 * @throws IllegalAccessException if the requested method is not accessible 247 * via reflection 248 */ 249 public static Object invokeExactMethod(Object object, String methodName, 250 Object[] args, Class[] parameterTypes) 251 throws NoSuchMethodException, IllegalAccessException, 252 InvocationTargetException { 253 if (args == null) { 254 args = ArrayUtils.EMPTY_OBJECT_ARRAY; 255 } 256 if (parameterTypes == null) { 257 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY; 258 } 259 Method method = getAccessibleMethod(object.getClass(), methodName, 260 parameterTypes); 261 if (method == null) { 262 throw new NoSuchMethodException("No such accessible method: " 263 + methodName + "() on object: " 264 + object.getClass().getName()); 265 } 266 return method.invoke(object, args); 267 } 268 269 /** 270 * <p>Invoke a static method whose parameter types match exactly the parameter 271 * types given.</p> 272 * 273 * <p>This uses reflection to invoke the method obtained from a call to 274 * {@link #getAccessibleMethod(Class, String, Class[])}.</p> 275 * 276 * @param cls invoke static method on this class 277 * @param methodName get method with this name 278 * @param args use these arguments - treat null as empty array 279 * @param parameterTypes match these parameters - treat null as empty array 280 * @return The value returned by the invoked method 281 * 282 * @throws NoSuchMethodException if there is no such accessible method 283 * @throws InvocationTargetException wraps an exception thrown by the 284 * method invoked 285 * @throws IllegalAccessException if the requested method is not accessible 286 * via reflection 287 */ 288 public static Object invokeExactStaticMethod(Class cls, String methodName, 289 Object[] args, Class[] parameterTypes) 290 throws NoSuchMethodException, IllegalAccessException, 291 InvocationTargetException { 292 if (args == null) { 293 args = ArrayUtils.EMPTY_OBJECT_ARRAY; 294 } 295 if (parameterTypes == null) { 296 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY; 297 } 298 Method method = getAccessibleMethod(cls, methodName, parameterTypes); 299 if (method == null) { 300 throw new NoSuchMethodException("No such accessible method: " 301 + methodName + "() on class: " + cls.getName()); 302 } 303 return method.invoke(null, args); 304 } 305 306 /** 307 * <p>Invoke a named static method whose parameter type matches the object type.</p> 308 * 309 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p> 310 * 311 * <p>This method supports calls to methods taking primitive parameters 312 * via passing in wrapping classes. So, for example, a <code>Boolean</code> class 313 * would match a <code>boolean</code> primitive.</p> 314 * 315 * <p> This is a convenient wrapper for 316 * {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args)}. 317 * </p> 318 * 319 * @param cls invoke static method on this class 320 * @param methodName get method with this name 321 * @param arg use this argument 322 * @return The value returned by the invoked method 323 * 324 * @throws NoSuchMethodException if there is no such accessible method 325 * @throws InvocationTargetException wraps an exception thrown by the 326 * method invoked 327 * @throws IllegalAccessException if the requested method is not accessible 328 * via reflection 329 */ 330 public static Object invokeStaticMethod(Class cls, String methodName, 331 Object arg) throws NoSuchMethodException, IllegalAccessException, 332 InvocationTargetException { 333 return invokeStaticMethod(cls, methodName, new Object[] { arg }); 334 } 335 336 /** 337 * <p>Invoke a named static method whose parameter type matches the object type.</p> 338 * 339 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p> 340 * 341 * <p>This method supports calls to methods taking primitive parameters 342 * via passing in wrapping classes. So, for example, a <code>Boolean</code> class 343 * would match a <code>boolean</code> primitive.</p> 344 * 345 * <p> This is a convenient wrapper for 346 * {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}. 347 * </p> 348 * 349 * @param cls invoke static method on this class 350 * @param methodName get method with this name 351 * @param args use these arguments - treat null as empty array 352 * @return The value returned by the invoked method 353 * 354 * @throws NoSuchMethodException if there is no such accessible method 355 * @throws InvocationTargetException wraps an exception thrown by the 356 * method invoked 357 * @throws IllegalAccessException if the requested method is not accessible 358 * via reflection 359 */ 360 public static Object invokeStaticMethod(Class cls, String methodName, 361 Object[] args) throws NoSuchMethodException, 362 IllegalAccessException, InvocationTargetException { 363 if (args == null) { 364 args = ArrayUtils.EMPTY_OBJECT_ARRAY; 365 } 366 int arguments = args.length; 367 Class[] parameterTypes = new Class[arguments]; 368 for (int i = 0; i < arguments; i++) { 369 parameterTypes[i] = args[i].getClass(); 370 } 371 return invokeStaticMethod(cls, methodName, args, parameterTypes); 372 } 373 374 /** 375 * <p>Invoke a named static method whose parameter type matches the object type.</p> 376 * 377 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p> 378 * 379 * <p>This method supports calls to methods taking primitive parameters 380 * via passing in wrapping classes. So, for example, a <code>Boolean</code> class 381 * would match a <code>boolean</code> primitive.</p> 382 * 383 * 384 * @param cls invoke static method on this class 385 * @param methodName get method with this name 386 * @param args use these arguments - treat null as empty array 387 * @param parameterTypes match these parameters - treat null as empty array 388 * @return The value returned by the invoked method 389 * 390 * @throws NoSuchMethodException if there is no such accessible method 391 * @throws InvocationTargetException wraps an exception thrown by the 392 * method invoked 393 * @throws IllegalAccessException if the requested method is not accessible 394 * via reflection 395 */ 396 public static Object invokeStaticMethod(Class cls, String methodName, 397 Object[] args, Class[] parameterTypes) 398 throws NoSuchMethodException, IllegalAccessException, 399 InvocationTargetException { 400 if (parameterTypes == null) { 401 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY; 402 } 403 if (args == null) { 404 args = ArrayUtils.EMPTY_OBJECT_ARRAY; 405 } 406 Method method = getMatchingAccessibleMethod(cls, methodName, 407 parameterTypes); 408 if (method == null) { 409 throw new NoSuchMethodException("No such accessible method: " 410 + methodName + "() on class: " + cls.getName()); 411 } 412 return method.invoke(null, args); 413 } 414 415 /** 416 * <p>Invoke a static method whose parameter type matches exactly the object 417 * type.</p> 418 * 419 * <p> This is a convenient wrapper for 420 * {@link #invokeExactStaticMethod(Class objectClass,String methodName,Object [] args)}. 421 * </p> 422 * 423 * @param cls invoke static method on this class 424 * @param methodName get method with this name 425 * @param arg use this argument 426 * @return The value returned by the invoked method 427 * 428 * @throws NoSuchMethodException if there is no such accessible method 429 * @throws InvocationTargetException wraps an exception thrown by the 430 * method invoked 431 * @throws IllegalAccessException if the requested method is not accessible 432 * via reflection 433 */ 434 public static Object invokeExactStaticMethod(Class cls, String methodName, 435 Object arg) throws NoSuchMethodException, IllegalAccessException, 436 InvocationTargetException { 437 return invokeExactStaticMethod(cls, methodName, new Object[] { arg }); 438 } 439 440 /** 441 * <p>Invoke a static method whose parameter types match exactly the object 442 * types.</p> 443 * 444 * <p> This uses reflection to invoke the method obtained from a call to 445 * {@link #getAccessibleMethod(Class, String, Class[])}.</p> 446 * 447 * @param cls invoke static method on this class 448 * @param methodName get method with this name 449 * @param args use these arguments - treat null as empty array 450 * @return The value returned by the invoked method 451 * 452 * @throws NoSuchMethodException if there is no such accessible method 453 * @throws InvocationTargetException wraps an exception thrown by the 454 * method invoked 455 * @throws IllegalAccessException if the requested method is not accessible 456 * via reflection 457 */ 458 public static Object invokeExactStaticMethod(Class cls, String methodName, 459 Object[] args) throws NoSuchMethodException, 460 IllegalAccessException, InvocationTargetException { 461 if (args == null) { 462 args = ArrayUtils.EMPTY_OBJECT_ARRAY; 463 } 464 int arguments = args.length; 465 Class[] parameterTypes = new Class[arguments]; 466 for (int i = 0; i < arguments; i++) { 467 parameterTypes[i] = args[i].getClass(); 468 } 469 return invokeExactStaticMethod(cls, methodName, args, parameterTypes); 470 } 471 472 /** 473 * <p>Return an accessible method (that is, one that can be invoked via 474 * reflection) with given name and a single parameter. If no such method 475 * can be found, return <code>null</code>. 476 * Basically, a convenience wrapper that constructs a <code>Class</code> 477 * array for you.</p> 478 * 479 * @param cls get method from this class 480 * @param methodName get method with this name 481 * @param parameterType taking this type of parameter 482 * @return The accessible method 483 */ 484 public static Method getAccessibleMethod(Class cls, String methodName, 485 Class parameterType) { 486 return getAccessibleMethod(cls, methodName, 487 new Class[] { parameterType }); 488 } 489 490 /** 491 * <p>Return an accessible method (that is, one that can be invoked via 492 * reflection) with given name and parameters. If no such method 493 * can be found, return <code>null</code>. 494 * This is just a convenient wrapper for 495 * {@link #getAccessibleMethod(Method method)}.</p> 496 * 497 * @param cls get method from this class 498 * @param methodName get method with this name 499 * @param parameterTypes with these parameters types 500 * @return The accessible method 501 */ 502 public static Method getAccessibleMethod(Class cls, String methodName, 503 Class[] parameterTypes) { 504 try { 505 return getAccessibleMethod(cls.getMethod(methodName, 506 parameterTypes)); 507 } catch (NoSuchMethodException e) { 508 return (null); 509 } 510 } 511 512 /** 513 * <p>Return an accessible method (that is, one that can be invoked via 514 * reflection) that implements the specified Method. If no such method 515 * can be found, return <code>null</code>.</p> 516 * 517 * @param method The method that we wish to call 518 * @return The accessible method 519 */ 520 public static Method getAccessibleMethod(Method method) { 521 if (!MemberUtils.isAccessible(method)) { 522 return null; 523 } 524 // If the declaring class is public, we are done 525 Class cls = method.getDeclaringClass(); 526 if (Modifier.isPublic(cls.getModifiers())) { 527 return method; 528 } 529 String methodName = method.getName(); 530 Class[] parameterTypes = method.getParameterTypes(); 531 532 // Check the implemented interfaces and subinterfaces 533 method = getAccessibleMethodFromInterfaceNest(cls, methodName, 534 parameterTypes); 535 536 // Check the superclass chain 537 if (method == null) { 538 method = getAccessibleMethodFromSuperclass(cls, methodName, 539 parameterTypes); 540 } 541 return method; 542 } 543 544 /** 545 * <p>Return an accessible method (that is, one that can be invoked via 546 * reflection) by scanning through the superclasses. If no such method 547 * can be found, return <code>null</code>.</p> 548 * 549 * @param cls Class to be checked 550 * @param methodName Method name of the method we wish to call 551 * @param parameterTypes The parameter type signatures 552 * @return the accessible method or <code>null</code> if not found 553 */ 554 private static Method getAccessibleMethodFromSuperclass(Class cls, 555 String methodName, Class[] parameterTypes) { 556 Class parentClass = cls.getSuperclass(); 557 while (parentClass != null) { 558 if (Modifier.isPublic(parentClass.getModifiers())) { 559 try { 560 return parentClass.getMethod(methodName, parameterTypes); 561 } catch (NoSuchMethodException e) { 562 return null; 563 } 564 } 565 parentClass = parentClass.getSuperclass(); 566 } 567 return null; 568 } 569 570 /** 571 * <p>Return an accessible method (that is, one that can be invoked via 572 * reflection) that implements the specified method, by scanning through 573 * all implemented interfaces and subinterfaces. If no such method 574 * can be found, return <code>null</code>.</p> 575 * 576 * <p> There isn't any good reason why this method must be private. 577 * It is because there doesn't seem any reason why other classes should 578 * call this rather than the higher level methods.</p> 579 * 580 * @param cls Parent class for the interfaces to be checked 581 * @param methodName Method name of the method we wish to call 582 * @param parameterTypes The parameter type signatures 583 * @return the accessible method or <code>null</code> if not found 584 */ 585 private static Method getAccessibleMethodFromInterfaceNest(Class cls, 586 String methodName, Class[] parameterTypes) { 587 Method method = null; 588 589 // Search up the superclass chain 590 for (; cls != null; cls = cls.getSuperclass()) { 591 592 // Check the implemented interfaces of the parent class 593 Class[] interfaces = cls.getInterfaces(); 594 for (int i = 0; i < interfaces.length; i++) { 595 // Is this interface public? 596 if (!Modifier.isPublic(interfaces[i].getModifiers())) { 597 continue; 598 } 599 // Does the method exist on this interface? 600 try { 601 method = interfaces[i].getDeclaredMethod(methodName, 602 parameterTypes); 603 } catch (NoSuchMethodException e) { 604 /* 605 * Swallow, if no method is found after the loop then this 606 * method returns null. 607 */ 608 } 609 if (method != null) { 610 break; 611 } 612 // Recursively check our parent interfaces 613 method = getAccessibleMethodFromInterfaceNest(interfaces[i], 614 methodName, parameterTypes); 615 if (method != null) { 616 break; 617 } 618 } 619 } 620 return method; 621 } 622 623 /** 624 * <p>Find an accessible method that matches the given name and has compatible parameters. 625 * Compatible parameters mean that every method parameter is assignable from 626 * the given parameters. 627 * In other words, it finds a method with the given name 628 * that will take the parameters given.<p> 629 * 630 * <p>This method is used by 631 * {@link 632 * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}. 633 * 634 * <p>This method can match primitive parameter by passing in wrapper classes. 635 * For example, a <code>Boolean</code> will match a primitive <code>boolean</code> 636 * parameter. 637 * 638 * @param cls find method in this class 639 * @param methodName find method with this name 640 * @param parameterTypes find method with most compatible parameters 641 * @return The accessible method 642 */ 643 public static Method getMatchingAccessibleMethod(Class cls, 644 String methodName, Class[] parameterTypes) { 645 try { 646 Method method = cls.getMethod(methodName, parameterTypes); 647 MemberUtils.setAccessibleWorkaround(method); 648 return method; 649 } catch (NoSuchMethodException e) { /* SWALLOW */ 650 } 651 // search through all methods 652 Method bestMatch = null; 653 Method[] methods = cls.getMethods(); 654 for (int i = 0, size = methods.length; i < size; i++) { 655 if (methods[i].getName().equals(methodName)) { 656 // compare parameters 657 if (ClassUtils.isAssignable(parameterTypes, methods[i] 658 .getParameterTypes(), true)) { 659 // get accessible version of method 660 Method accessibleMethod = getAccessibleMethod(methods[i]); 661 if (accessibleMethod != null) { 662 if (bestMatch == null 663 || MemberUtils.compareParameterTypes( 664 accessibleMethod.getParameterTypes(), 665 bestMatch.getParameterTypes(), 666 parameterTypes) < 0) { 667 bestMatch = accessibleMethod; 668 } 669 } 670 } 671 } 672 } 673 if (bestMatch != null) { 674 MemberUtils.setAccessibleWorkaround(bestMatch); 675 } 676 return bestMatch; 677 } 678 }