View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.reflect;
18  
19  import static org.apache.commons.lang3.LangAssertions.assertNullPointerException;
20  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNotSame;
25  import static org.junit.jupiter.api.Assertions.assertNull;
26  import static org.junit.jupiter.api.Assertions.assertSame;
27  import static org.junit.jupiter.api.Assertions.assertThrows;
28  import static org.junit.jupiter.api.Assertions.assertTrue;
29  import static org.junit.jupiter.api.Assumptions.assumeTrue;
30  
31  import java.awt.Color;
32  import java.lang.reflect.Method;
33  import java.lang.reflect.Modifier;
34  import java.lang.reflect.Type;
35  import java.nio.file.Files;
36  import java.nio.file.LinkOption;
37  import java.nio.file.Path;
38  import java.util.ArrayList;
39  import java.util.Arrays;
40  import java.util.Collections;
41  import java.util.Date;
42  import java.util.HashMap;
43  import java.util.Iterator;
44  import java.util.List;
45  import java.util.Map;
46  
47  import org.apache.commons.lang3.AbstractLangTest;
48  import org.apache.commons.lang3.ArrayUtils;
49  import org.apache.commons.lang3.ClassUtils;
50  import org.apache.commons.lang3.ClassUtils.Interfaces;
51  import org.apache.commons.lang3.JavaVersion;
52  import org.apache.commons.lang3.SystemUtils;
53  import org.apache.commons.lang3.math.NumberUtils;
54  import org.apache.commons.lang3.mutable.Mutable;
55  import org.apache.commons.lang3.mutable.MutableObject;
56  import org.apache.commons.lang3.reflect.testbed.Annotated;
57  import org.apache.commons.lang3.reflect.testbed.GenericConsumer;
58  import org.apache.commons.lang3.reflect.testbed.GenericParent;
59  import org.apache.commons.lang3.reflect.testbed.PublicChild;
60  import org.apache.commons.lang3.reflect.testbed.PublicSubBeanOtherPackage;
61  import org.apache.commons.lang3.reflect.testbed.StringParameterizedChild;
62  import org.apache.commons.lang3.tuple.ImmutablePair;
63  import org.junit.jupiter.api.BeforeEach;
64  import org.junit.jupiter.api.Test;
65  import org.junit.jupiter.params.ParameterizedTest;
66  import org.junit.jupiter.params.provider.ValueSource;
67  
68  /**
69   * {@link Tests MethodUtils}.
70   */
71  class MethodUtilsTest extends AbstractLangTest {
72  
73      protected abstract static class AbstractGetMatchingMethod implements InterfaceGetMatchingMethod {
74          public abstract void testMethod5(Exception exception);
75      }
76  
77      protected abstract static class AbstractGetMatchingMethod2 implements InterfaceGetMatchingMethod {
78          @Override
79          public void testMethod6() { }
80      }
81  
82      public static class ChildObject extends ParentObject implements PackagePrivateEmptyInterface {
83      }
84  
85      private static final class ConcreteGetMatchingMethod2 extends AbstractGetMatchingMethod2 { }
86  
87      private static final class ConcreteGetMatchingMethod22 extends AbstractGetMatchingMethod2 {
88          @Override
89          public void testMethod6() { }
90      }
91  
92      private static final class GetMatchingMethodClass {
93  
94          public void testMethod() {
95          }
96  
97          public void testMethod(final long aLong) {
98          }
99  
100         public void testMethod(final Long aLong) {
101         }
102 
103         public void testMethod2(final Color aColor) {
104         }
105 
106         public void testMethod2(final long aLong) {
107         }
108 
109         public void testMethod2(final Long aLong) {
110         }
111 
112         public void testMethod3(final long aLong, final Long anotherLong) {
113         }
114 
115         public void testMethod3(final Long aLong, final long anotherLong) {
116         }
117 
118         public void testMethod3(final Long aLong, final Long anotherLong) {
119         }
120 
121         public void testMethod4(final Color aColor1, final Color aColor2) {
122         }
123 
124         public void testMethod4(final Long aLong, final Long anotherLong) {
125         }
126 
127         public void testMethod5(final Integer anInteger) {
128         }
129 
130         public void testMethod5(final Number aNumber) {
131         }
132     }
133 
134     private static final class GetMatchingMethodImpl extends AbstractGetMatchingMethod {
135         @Override
136         public void testMethod5(final Exception exception) {
137         }
138     }
139 
140     public static class GrandParentObject {
141     }
142     public static class InheritanceBean {
143         public void testOne(final GrandParentObject obj) {
144         }
145 
146         public void testOne(final Object obj) {
147         }
148 
149         public void testOne(final ParentObject obj) {
150         }
151 
152         public void testTwo(final GrandParentObject obj) {
153         }
154 
155         public void testTwo(final Object obj) {
156         }
157 
158         public void testTwo(final PackagePrivateEmptyInterface obj) {
159         }
160     }
161 
162     static class InstanceLabel implements StaticLabel {
163         public String label() {
164             return "instance";
165         }
166     }
167     interface InterfaceGetMatchingMethod {
168         default void testMethod6() {
169         }
170     }
171 
172     private static final class MethodDescriptor {
173         final Class<?> declaringClass;
174         final String name;
175         final Type[] parameterTypes;
176 
177         MethodDescriptor(final Class<?> declaringClass, final String name, final Type... parameterTypes) {
178             this.declaringClass = declaringClass;
179             this.name = name;
180             this.parameterTypes = parameterTypes;
181         }
182     }
183 
184     interface PackagePrivateEmptyInterface {
185         // empty
186     }
187 
188     public static class ParentObject extends GrandParentObject {
189         // empty
190     }
191 
192     private interface PrivateEmptyInterface {
193         // empty
194     }
195 
196     public static class PublicImpl1OfPackagePrivateEmptyInterface implements PackagePrivateEmptyInterface {
197         // empty
198     }
199 
200     public static class PublicImpl2OfPackagePrivateEmptyInterface implements PackagePrivateEmptyInterface {
201         // empty
202     }
203 
204     static class StaticChild extends StaticParent {
205         public static String who() {
206             return "child";
207         }
208     }
209 
210     public interface StaticLabel {
211         static String label() {
212             return "interface";
213         }
214     }
215 
216     public static class StaticParent {
217         public static String who() {
218             return "parent";
219         }
220     }
221 
222     public static class TestBean {
223 
224         public static String bar() {
225             return "bar()";
226         }
227 
228         public static String bar(final double d) {
229             return "bar(double)";
230         }
231 
232         public static String bar(final int i) {
233             return "bar(int)";
234         }
235 
236         public static String bar(final Integer i) {
237             return "bar(Integer)";
238         }
239 
240         public static String bar(final Integer i, final String... s) {
241             return "bar(Integer, String...)";
242         }
243 
244         public static String bar(final long... s) {
245             return "bar(long...)";
246         }
247 
248         public static String bar(final Object o) {
249             return "bar(Object)";
250         }
251 
252         public static String bar(final String s) {
253             return "bar(String)";
254         }
255 
256         public static String bar(final String... s) {
257             return "bar(String...)";
258         }
259 
260         // This method is overloaded for the wrapper class for every numeric primitive type, plus the common
261         // supertype Number
262         public static String numOverload(final Byte... args) {
263             return "Byte...";
264         }
265 
266         public static String numOverload(final Double... args) {
267             return "Double...";
268         }
269 
270         public static String numOverload(final Float... args) {
271             return "Float...";
272         }
273 
274         public static String numOverload(final Integer... args) {
275             return "Integer...";
276         }
277 
278         public static String numOverload(final Long... args) {
279             return "Long...";
280         }
281 
282         public static String numOverload(final Number... args) {
283             return "Number...";
284         }
285 
286         public static String numOverload(final Short... args) {
287             return "Short...";
288         }
289 
290         public static void oneParameterStatic(final String s) {
291             // empty
292         }
293 
294         public static String staticInt(final int intArg) {
295             return "static int";
296         }
297 
298         public static String staticIntIntVarArg(final int intArg, final int... args) {
299             return "static int, int...";
300         }
301 
302         public static String staticIntLongVarArg(final int intArg, final long... args) {
303             return "static int, long...";
304         }
305 
306         public static String staticIntStringVarArg(final int intArg, final String... args) {
307             return "static int, String...";
308         }
309 
310         public static String staticPackagePrivateEmptyInterface(final PackagePrivateEmptyInterface... args) {
311             return "static PackagePrivateEmptyInterface...";
312         }
313 
314         public static String varOverload(final Boolean... args) {
315             return "Boolean...";
316         }
317 
318         // This method is overloaded for the wrapper class for every primitive type, plus the common supertypes
319         // Number and Object. This is an acid test since it easily leads to ambiguous methods.
320         public static String varOverload(final Byte... args) {
321             return "Byte...";
322         }
323 
324         public static String varOverload(final Character... args) {
325             return "Character...";
326         }
327 
328         public static String varOverload(final Double... args) {
329             return "Double...";
330         }
331 
332         public static String varOverload(final Float... args) {
333             return "Float...";
334         }
335 
336         public static String varOverload(final Integer... args) {
337             return "Integer...";
338         }
339 
340         public static String varOverload(final Long... args) {
341             return "Long...";
342         }
343 
344         public static String varOverload(final Number... args) {
345             return "Number...";
346         }
347 
348         public static String varOverload(final Object... args) {
349             return "Object...";
350         }
351 
352         public static String varOverload(final Short... args) {
353             return "Short...";
354         }
355 
356         public static String varOverload(final String... args) {
357             return "String...";
358         }
359 
360         public static ImmutablePair<String, Object[]> varOverloadEchoStatic(final Number... args) {
361             return new ImmutablePair<>("Number...", args);
362         }
363 
364         public static ImmutablePair<String, Object[]> varOverloadEchoStatic(final String... args) {
365             return new ImmutablePair<>("String...", args);
366         }
367 
368         static void verify(final ImmutablePair<String, Object[]> a, final ImmutablePair<String, Object[]> b) {
369             assertEquals(a.getLeft(), b.getLeft());
370             assertArrayEquals(a.getRight(), b.getRight());
371         }
372 
373         static void verify(final ImmutablePair<String, Object[]> a, final Object obj) {
374             @SuppressWarnings("unchecked")
375             final ImmutablePair<String, Object[]> pair = (ImmutablePair<String, Object[]>) obj;
376             verify(a, pair);
377         }
378 
379         boolean unboxBooleanArray;
380 
381         boolean unboxByteArray;
382 
383         boolean unboxCharArray;
384 
385         boolean unboxDoubleArray;
386 
387         boolean unboxFloatArray;
388 
389         boolean unboxIntArray;
390 
391         boolean unboxLongArray;
392 
393         boolean unboxShortArray;
394 
395         public String foo() {
396             return "foo()";
397         }
398 
399         public String foo(final double d) {
400             return "foo(double)";
401         }
402 
403         public String foo(final int i) {
404             return "foo(int)";
405         }
406 
407         public String foo(final Integer i) {
408             return "foo(Integer)";
409         }
410 
411         public String foo(final Integer i, final String... s) {
412             return "foo(int, String...)";
413         }
414 
415         public String foo(final long l) {
416             return "foo(long)";
417         }
418 
419         public String foo(final long... l) {
420             return "foo(long...)";
421         }
422 
423         public String foo(final Object o) {
424             return "foo(Object)";
425         }
426 
427         public String foo(final Object... s) {
428             return "foo(Object...)";
429         }
430 
431         public String foo(final String s) {
432             return "foo(String)";
433         }
434 
435         public String foo(final String... s) {
436             return "foo(String...)";
437         }
438 
439         public String intIntVarArg(final int intArg, final int... args) {
440             return "int, int...";
441         }
442 
443         public String intLongVarArg(final int intArg, final long... args) {
444             return "int, long...";
445         }
446 
447         public String intStringVarArg(final int intArg, final String... args) {
448             return "int, String...";
449         }
450 
451         public void oneParameter(final String s) {
452             // empty
453         }
454 
455         public String packagePrivateEmptyInterface(final PackagePrivateEmptyInterface... args) {
456             return "PackagePrivateEmptyInterface...";
457         }
458 
459         @SuppressWarnings("unused")
460         private String privateStringStuff() {
461             return "privateStringStuff()";
462         }
463 
464         @SuppressWarnings("unused")
465         private String privateStringStuff(final double d) {
466             return "privateStringStuff(double)";
467         }
468 
469         @SuppressWarnings("unused")
470         private String privateStringStuff(final int i) {
471             return "privateStringStuff(int)";
472         }
473 
474         @SuppressWarnings("unused")
475         private String privateStringStuff(final Integer i) {
476             return "privateStringStuff(Integer)";
477         }
478 
479         @SuppressWarnings("unused")
480         private String privateStringStuff(final Object s) {
481             return "privateStringStuff(Object)";
482         }
483 
484         @SuppressWarnings("unused")
485         private String privateStringStuff(final String s) {
486             return "privateStringStuff(String)";
487         }
488 
489         @SuppressWarnings("unused")
490         private void privateStuff() {
491         }
492 
493         public boolean[] unboxing(final boolean... values) {
494             unboxBooleanArray = true;
495             return values;
496         }
497 
498         public byte[] unboxing(final byte... values) {
499             unboxByteArray = true;
500             return values;
501         }
502 
503         public char[] unboxing(final char... values) {
504             unboxCharArray = true;
505             return values;
506         }
507 
508         public double[] unboxing(final double... values) {
509             unboxDoubleArray = true;
510             return values;
511         }
512 
513         public float[] unboxing(final float... values) {
514             unboxFloatArray = true;
515             return values;
516         }
517 
518         public int[] unboxing(final int... values) {
519             unboxIntArray = true;
520             return values;
521         }
522 
523         public long[] unboxing(final long... values) {
524             unboxLongArray = true;
525             return values;
526         }
527 
528         public short[] unboxing(final short... values) {
529             unboxShortArray = true;
530             return values;
531         }
532 
533         public ImmutablePair<String, Object[]> varOverloadEcho(final Number... args) {
534             return new ImmutablePair<>("Number...", args);
535         }
536 
537         // These varOverloadEcho and varOverloadEchoStatic methods are designed to verify that
538         // not only is the correct overloaded variant invoked, but that the varargs arguments
539         // are also delivered correctly to the method.
540         public ImmutablePair<String, Object[]> varOverloadEcho(final String... args) {
541             return new ImmutablePair<>("String...", args);
542         }
543 
544     }
545 
546     static class TestBeanSubclass extends TestBean {
547     }
548 
549     static class TestBeanWithInterfaces implements PrivateEmptyInterface {
550         public String foo() {
551             return "foo()";
552         }
553     }
554 
555     private static class TestMutable implements Mutable<Object> {
556         @Override
557         public Object getValue() {
558             return null;
559         }
560 
561         @Override
562         public void setValue(final Object value) {
563         }
564     }
565 
566     private static final class TestMutableSubclass extends TestMutable {
567         // empty
568     }
569 
570     private final Map<Class<?>, Class<?>[]> classCache = new HashMap<>();
571 
572     private TestBean testBean;
573 
574     private void expectMatchingAccessibleMethodParameterTypes(final Class<?> cls, final String methodName, final Class<?>[] requestTypes,
575             final Class<?>[] actualTypes) {
576         final Method m = MethodUtils.getMatchingAccessibleMethod(cls, methodName, requestTypes);
577         assertNotNull(m, "could not find any matches for " + methodName + " (" + (requestTypes == null ? null : toString(requestTypes)) + ")");
578         assertArrayEquals(actualTypes, m.getParameterTypes(), toString(m.getParameterTypes()) + " not equals " + toString(actualTypes));
579     }
580 
581     @BeforeEach
582     public void setUp() {
583         testBean = new TestBean();
584         classCache.clear();
585     }
586 
587     private Class<?>[] singletonArray(final Class<?> c) {
588         Class<?>[] result = classCache.get(c);
589         if (result == null) {
590             result = new Class[]{c};
591             classCache.put(c, result);
592         }
593         return result;
594     }
595 
596     @Test
597     void testConstructor() throws Exception {
598         assertNotNull(MethodUtils.class.getConstructor().newInstance());
599     }
600 
601     @Test
602     void testDistance() throws Exception {
603         final Method distanceMethod = MethodUtils.getMatchingMethod(MethodUtils.class, "distance", Class[].class, Class[].class);
604         distanceMethod.setAccessible(true);
605         assertEquals(-1, distanceMethod.invoke(null, new Class[] { String.class }, new Class[] { Date.class }));
606         assertEquals(0, distanceMethod.invoke(null, new Class[] { Date.class }, new Class[] { Date.class }));
607         assertEquals(1, distanceMethod.invoke(null, new Class[] { Integer.class }, new Class[] { ClassUtils.wrapperToPrimitive(Integer.class) }));
608         assertEquals(2, distanceMethod.invoke(null, new Class[] { Integer.class }, new Class[] { Object.class }));
609         distanceMethod.setAccessible(false);
610     }
611 
612     @ParameterizedTest
613     @ValueSource(classes = {TestMutable.class, TestMutableSubclass.class})
614     void testGetAccessibleInterfaceMethod(final Class<?> clazz) throws Exception {
615         final Class<?>[][] p = {ArrayUtils.EMPTY_CLASS_ARRAY, null};
616         for (final Class<?>[] element : p) {
617             final Method method = clazz.getMethod("getValue", element);
618             final Method accessibleMethod = MethodUtils.getAccessibleMethod(method);
619             assertNotSame(accessibleMethod, method);
620             assertSame(Mutable.class, accessibleMethod.getDeclaringClass());
621             final Method accessibleMethod2 = MethodUtils.getAccessibleMethod(clazz, method);
622             assertNotSame(accessibleMethod2, method);
623             assertSame(Mutable.class, accessibleMethod2.getDeclaringClass());
624         }
625     }
626 
627     @ParameterizedTest
628     @ValueSource(classes = {TestMutable.class, TestMutableSubclass.class})
629     void testGetAccessibleInterfaceMethodFromDescription(final Class<?> clazz) {
630         final Class<?>[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null };
631         for (final Class<?>[] element : p) {
632             final Method accessibleMethod = MethodUtils.getAccessibleMethod(clazz, "getValue", element);
633             assertSame(Mutable.class, accessibleMethod.getDeclaringClass());
634         }
635     }
636 
637     @Test
638     void testGetAccessibleMethodInaccessible() throws Exception {
639         assertNull(MethodUtils.getAccessibleMethod(TestBean.class.getDeclaredMethod("privateStuff")));
640         assertNull(MethodUtils.getAccessibleMethod(TestBean.class, TestBean.class.getDeclaredMethod("privateStuff")));
641         assertNull(MethodUtils.getAccessibleMethod(TestBeanSubclass.class, TestBean.class.getDeclaredMethod("privateStuff")));
642     }
643 
644     @Test
645     void testGetAccessibleMethodPrivateInterface() throws Exception {
646         final Method expected = TestBeanWithInterfaces.class.getMethod("foo");
647         assertNotNull(expected);
648         final Method actual = MethodUtils.getAccessibleMethod(TestBeanWithInterfaces.class, "foo");
649         assertNull(actual);
650     }
651 
652     @Test
653     void testGetAccessibleMethodPublicSub() throws Exception {
654         // PackageBean class is package-private
655         final int modifiers = PackageBean.class.getModifiers();
656         assertFalse(Modifier.isPrivate(modifiers));
657         assertFalse(Modifier.isProtected(modifiers));
658         assertFalse(Modifier.isPublic(modifiers));
659         // make sure that bean does what it should: compile
660         new PublicSubBean().setBar("");
661         // make sure that bean does what it should
662         final PublicSubBean bean = new PublicSubBean();
663         assertEquals(bean.getFoo(), "This is foo", "Start value (foo)");
664         assertEquals(bean.getBar(), "This is bar", "Start value (bar)");
665         bean.setFoo("new foo");
666         bean.setBar("new bar");
667         assertEquals(bean.getFoo(), "new foo", "Set value (foo)");
668         assertEquals(bean.getBar(), "new bar", "Set value (bar)");
669         // see if we can access public methods in a default access superclass
670         // from a public access subclass instance
671         MethodUtils.invokeExactMethod(bean, "setFoo", "alpha");
672         assertEquals(bean.getFoo(), "alpha", "Set value (foo:2)");
673         MethodUtils.invokeExactMethod(bean, "setBar", "beta");
674         assertEquals(bean.getBar(), "beta", "Set value (bar:2)");
675         // PublicSubBean.setFoo(String)
676         Method method = MethodUtils.getAccessibleMethod(PublicSubBean.class, "setFoo", String.class);
677         assertNotNull(method, "getAccessibleMethod() setFoo is Null");
678         method.invoke(bean, "1111");
679         assertEquals("1111", bean.getFoo(), "Set value (foo:3)");
680         // PublicSubBean.setBar(String)
681         method = MethodUtils.getAccessibleMethod(PublicSubBean.class, "setBar", String.class);
682         assertNotNull(method, "getAccessibleMethod() setBar is Null");
683         method.invoke(bean, "2222");
684         assertEquals("2222", bean.getBar(), "Set value (bar:3)");
685     }
686 
687     @Test
688     void testGetAccessibleMethodPublicSubOtherPackage() throws Exception {
689         // PackageBeanOtherPackage class is package-private
690         final int modifiers = Class.forName("org.apache.commons.lang3.reflect.testbed.PackageBeanOtherPackage").getModifiers();
691         assertFalse(Modifier.isPrivate(modifiers));
692         assertFalse(Modifier.isProtected(modifiers));
693         assertFalse(Modifier.isPublic(modifiers));
694         // make sure that bean does what it should: compile
695         new PublicSubBeanOtherPackage().setBar("");
696         // make sure that bean does what it should
697         final PublicSubBeanOtherPackage bean = new PublicSubBeanOtherPackage();
698         assertEquals(bean.getFoo(), "This is foo", "Start value (foo)");
699         assertEquals(bean.getBar(), "This is bar", "Start value (bar)");
700         bean.setFoo("new foo");
701         bean.setBar("new bar");
702         assertEquals(bean.getFoo(), "new foo", "Set value (foo)");
703         assertEquals(bean.getBar(), "new bar", "Set value (bar)");
704         // see if we can access public methods in a default access superclass
705         // from a public access subclass instance
706         MethodUtils.invokeExactMethod(bean, "setFoo", "alpha");
707         assertEquals(bean.getFoo(), "alpha", "Set value (foo:2)");
708         MethodUtils.invokeExactMethod(bean, "setBar", "beta");
709         assertEquals(bean.getBar(), "beta", "Set value (bar:2)");
710         // PublicSubBean.setFoo(String)
711         Method method = MethodUtils.getAccessibleMethod(PublicSubBeanOtherPackage.class, "setFoo", String.class);
712         assertNotNull(method, "getAccessibleMethod() setFoo is Null");
713         method.invoke(bean, "1111");
714         assertEquals("1111", bean.getFoo(), "Set value (foo:3)");
715         // PublicSubBean.setBar(String)
716         method = MethodUtils.getAccessibleMethod(PublicSubBeanOtherPackage.class, "setBar", String.class);
717         assertNotNull(method, "getAccessibleMethod() setBar is Null");
718         method.invoke(bean, "2222");
719         assertEquals("2222", bean.getBar(), "Set value (bar:3)");
720     }
721 
722     @Test
723     void testGetAccessiblePublicMethod() throws Exception {
724         assertSame(MutableObject.class,
725                 MethodUtils.getAccessibleMethod(MutableObject.class.getMethod("getValue", ArrayUtils.EMPTY_CLASS_ARRAY)).getDeclaringClass());
726         assertSame(MutableObject.class, MethodUtils
727                 .getAccessibleMethod(MutableObject.class, MutableObject.class.getMethod("getValue", ArrayUtils.EMPTY_CLASS_ARRAY)).getDeclaringClass());
728     }
729 
730     @Test
731     void testGetAccessiblePublicMethodFromDescription() {
732         assertSame(MutableObject.class, MethodUtils.getAccessibleMethod(MutableObject.class, "getValue", ArrayUtils.EMPTY_CLASS_ARRAY).getDeclaringClass());
733     }
734 
735     @Test
736     void testGetAnnotationIllegalArgumentException1() {
737         assertNullPointerException(() -> MethodUtils.getAnnotation(FieldUtilsTest.class.getDeclaredMethods()[0], null, true, true));
738     }
739 
740     @Test
741     void testGetAnnotationIllegalArgumentException2() {
742         assertNullPointerException(() -> MethodUtils.getAnnotation(null, Annotated.class, true, true));
743     }
744 
745     @Test
746     void testGetAnnotationIllegalArgumentException3() {
747         assertNullPointerException(() -> MethodUtils.getAnnotation(null, null, true, true));
748     }
749 
750     @Test
751     void testGetAnnotationNotSearchSupersAndNotIgnoreAccess() throws NoSuchMethodException {
752         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("parentNotAnnotatedMethod"), Annotated.class, false, false));
753         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("doIt"), Annotated.class, false, false));
754         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("parentProtectedAnnotatedMethod"), Annotated.class, false, false));
755         assertNull(MethodUtils.getAnnotation(PublicChild.class.getDeclaredMethod("privateAnnotatedMethod"), Annotated.class, false, false));
756         assertNotNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("publicAnnotatedMethod"), Annotated.class, false, false));
757     }
758 
759     @Test
760     void testGetAnnotationNotSearchSupersButIgnoreAccess() throws NoSuchMethodException {
761         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("parentNotAnnotatedMethod"), Annotated.class, false, true));
762         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("doIt"), Annotated.class, false, true));
763         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("parentProtectedAnnotatedMethod"), Annotated.class, false, true));
764         assertNotNull(MethodUtils.getAnnotation(PublicChild.class.getDeclaredMethod("privateAnnotatedMethod"), Annotated.class, false, true));
765         assertNotNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("publicAnnotatedMethod"), Annotated.class, false, true));
766     }
767 
768     @Test
769     void testGetAnnotationSearchSupersAndIgnoreAccess() throws NoSuchMethodException {
770         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("parentNotAnnotatedMethod"), Annotated.class, true, true));
771         assertNotNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("doIt"), Annotated.class, true, true));
772         assertNotNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("parentProtectedAnnotatedMethod"), Annotated.class, true, true));
773         assertNotNull(MethodUtils.getAnnotation(PublicChild.class.getDeclaredMethod("privateAnnotatedMethod"), Annotated.class, true, true));
774         assertNotNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("publicAnnotatedMethod"), Annotated.class, true, true));
775         assertNull(MethodUtils.getAnnotation(StringParameterizedChild.class.getMethod("parentNotAnnotatedMethod", String.class), Annotated.class, true, true));
776         assertNotNull(MethodUtils.getAnnotation(StringParameterizedChild.class.getMethod("parentProtectedAnnotatedMethod", String.class), Annotated.class, true,
777                 true));
778         assertNotNull(MethodUtils.getAnnotation(StringParameterizedChild.class.getDeclaredMethod("privateAnnotatedMethod", String.class), Annotated.class, true,
779                 true));
780         assertNotNull(MethodUtils.getAnnotation(StringParameterizedChild.class.getMethod("publicAnnotatedMethod", String.class), Annotated.class, true, true));
781     }
782 
783     @Test
784     void testGetAnnotationSearchSupersButNotIgnoreAccess() throws NoSuchMethodException {
785         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("parentNotAnnotatedMethod"), Annotated.class, true, false));
786         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("doIt"), Annotated.class, true, false));
787         assertNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("parentProtectedAnnotatedMethod"), Annotated.class, true, false));
788         assertNull(MethodUtils.getAnnotation(PublicChild.class.getDeclaredMethod("privateAnnotatedMethod"), Annotated.class, true, false));
789         assertNotNull(MethodUtils.getAnnotation(PublicChild.class.getMethod("publicAnnotatedMethod"), Annotated.class, true, false));
790         assertNull(MethodUtils.getAnnotation(StringParameterizedChild.class.getMethod("parentNotAnnotatedMethod", String.class), Annotated.class, true, false));
791         assertNull(MethodUtils.getAnnotation(StringParameterizedChild.class.getMethod("parentProtectedAnnotatedMethod", String.class), Annotated.class, true,
792                 false));
793         assertNull(MethodUtils.getAnnotation(StringParameterizedChild.class.getDeclaredMethod("privateAnnotatedMethod", String.class), Annotated.class, true,
794                 false));
795         assertNotNull(MethodUtils.getAnnotation(StringParameterizedChild.class.getMethod("publicAnnotatedMethod", String.class), Annotated.class, true, false));
796     }
797 
798     @Test
799     void testGetMatchingAccessibleMethod() {
800         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY);
801         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", null, ArrayUtils.EMPTY_CLASS_ARRAY);
802         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(String.class), singletonArray(String.class));
803         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Object.class), singletonArray(Object.class));
804         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Boolean.class), singletonArray(Object.class));
805         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Byte.class), singletonArray(Integer.TYPE));
806         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Byte.TYPE), singletonArray(Integer.TYPE));
807         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Short.class), singletonArray(Integer.TYPE));
808         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Short.TYPE), singletonArray(Integer.TYPE));
809         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Character.class), singletonArray(Integer.TYPE));
810         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Character.TYPE), singletonArray(Integer.TYPE));
811         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Integer.class), singletonArray(Integer.class));
812         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Integer.TYPE), singletonArray(Integer.TYPE));
813         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Long.class), singletonArray(Long.TYPE));
814         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Long.TYPE), singletonArray(Long.TYPE));
815         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Float.class), singletonArray(Double.TYPE));
816         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Float.TYPE), singletonArray(Double.TYPE));
817         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Double.class), singletonArray(Double.TYPE));
818         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Double.TYPE), singletonArray(Double.TYPE));
819         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", singletonArray(Double.TYPE), singletonArray(Double.TYPE));
820         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", new Class[] { String.class, String.class }, new Class[] { String[].class });
821         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", new Class[] { Integer.TYPE, String.class, String.class },
822                 new Class[] { Integer.class, String[].class });
823         expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testOne", singletonArray(ParentObject.class), singletonArray(ParentObject.class));
824         expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testOne", singletonArray(ChildObject.class), singletonArray(ParentObject.class));
825         expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testTwo", singletonArray(ParentObject.class),
826                 singletonArray(GrandParentObject.class));
827         expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testTwo", singletonArray(ChildObject.class), singletonArray(PackagePrivateEmptyInterface.class));
828         // LANG-1757
829         expectMatchingAccessibleMethodParameterTypes(Files.class, "exists", singletonArray(Path.class), new Class[] { Path.class, LinkOption[].class });
830     }
831 
832     @ParameterizedTest
833     @ValueSource(classes = {TestMutable.class, TestMutableSubclass.class})
834     void testGetMatchingAccessibleMethodOnNonPublicClass(final Class<?> clazz) {
835         assertSame(Mutable.class, MethodUtils.getMatchingAccessibleMethod(clazz, "getValue").getDeclaringClass());
836         assertSame(Mutable.class,
837                 MethodUtils.getMatchingAccessibleMethod(clazz, "setValue", Object.class).getDeclaringClass());
838     }
839 
840     @Test
841     void testGetMatchingAccessibleMethodOnNonPublicJdkClass() {
842         assertSame(List.class,
843                 MethodUtils.getMatchingAccessibleMethod(Collections.emptyList().getClass(), "size").getDeclaringClass());
844         assertSame(List.class,
845                 MethodUtils.getMatchingAccessibleMethod(Arrays.asList(1, 2).getClass(), "size").getDeclaringClass());
846         assertSame(Map.class,
847                 MethodUtils.getMatchingAccessibleMethod(Collections.emptyMap().getClass(), "size").getDeclaringClass());
848     }
849 
850     @Test
851     void testGetMatchingAccessibleMethodWithNoPublicDeclaration() {
852         assertSame(TestBeanWithInterfaces.class,
853                 MethodUtils.getMatchingAccessibleMethod(TestBeanWithInterfaces.class, "foo").getDeclaringClass());
854     }
855 
856     @Test
857     void testGetMatchingMethod() throws NoSuchMethodException {
858         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod"), GetMatchingMethodClass.class.getMethod("testMethod"));
859         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod", Long.TYPE),
860                 GetMatchingMethodClass.class.getMethod("testMethod", Long.TYPE));
861         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod", Long.class),
862                 GetMatchingMethodClass.class.getMethod("testMethod", Long.class));
863         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod", (Class<?>) null),
864                 GetMatchingMethodClass.class.getMethod("testMethod", Long.class));
865         assertThrows(IllegalStateException.class, () -> MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod2", (Class<?>) null));
866         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod3", Long.TYPE, Long.class),
867                 GetMatchingMethodClass.class.getMethod("testMethod3", Long.TYPE, Long.class));
868         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod3", Long.class, Long.TYPE),
869                 GetMatchingMethodClass.class.getMethod("testMethod3", Long.class, Long.TYPE));
870         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod3", null, Long.TYPE),
871                 GetMatchingMethodClass.class.getMethod("testMethod3", Long.class, Long.TYPE));
872         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod3", Long.TYPE, null),
873                 GetMatchingMethodClass.class.getMethod("testMethod3", Long.TYPE, Long.class));
874         assertThrows(IllegalStateException.class, () -> MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod4", null, null));
875         // A primitive argument boxes to the exact wrapper overload, not to one of its supertypes.
876         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod5", Integer.TYPE),
877                 GetMatchingMethodClass.class.getMethod("testMethod5", Integer.class));
878         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodClass.class, "testMethod5", Integer.class),
879                 GetMatchingMethodClass.class.getMethod("testMethod5", Integer.class));
880         assertEquals(MethodUtils.getMatchingMethod(GetMatchingMethodImpl.class, "testMethod5", RuntimeException.class),
881                 GetMatchingMethodImpl.class.getMethod("testMethod5", Exception.class));
882         assertEquals(GetMatchingMethodImpl.class.getMethod("testMethod6"), MethodUtils.getMatchingMethod(GetMatchingMethodImpl.class, "testMethod6"));
883         assertNullPointerException(() -> MethodUtils.getMatchingMethod(null, "testMethod5", RuntimeException.class));
884         Method testMethod6 = MethodUtils.getMatchingMethod(ConcreteGetMatchingMethod2.class, "testMethod6");
885         assertNotNull(testMethod6);
886         assertEquals(AbstractGetMatchingMethod2.class, testMethod6.getDeclaringClass());
887         testMethod6 = MethodUtils.getMatchingMethod(ConcreteGetMatchingMethod22.class, "testMethod6");
888         assertNotNull(testMethod6);
889         assertEquals(ConcreteGetMatchingMethod22.class, testMethod6.getDeclaringClass());
890     }
891 
892     @Test
893     void testGetMethodObject() throws Exception {
894         assertEquals(MutableObject.class.getMethod("getValue", ArrayUtils.EMPTY_CLASS_ARRAY),
895                 MethodUtils.getMethodObject(MutableObject.class, "getValue", ArrayUtils.EMPTY_CLASS_ARRAY));
896         assertNull(MethodUtils.getMethodObject(MutableObject.class, "does not exist, at all", ArrayUtils.EMPTY_CLASS_ARRAY));
897         assertNull(MethodUtils.getMethodObject(null, "does not exist, at all", ArrayUtils.EMPTY_CLASS_ARRAY));
898         assertNull(MethodUtils.getMethodObject(null, null, ArrayUtils.EMPTY_CLASS_ARRAY));
899         assertNull(MethodUtils.getMethodObject(MutableObject.class, null, ArrayUtils.EMPTY_CLASS_ARRAY));
900         // 0 args
901         assertNull(MethodUtils.getMethodObject(MutableObject.class, "getValue", new Class[] { null }));
902         // 1 args
903         assertNull(MethodUtils.getMethodObject(MutableObject.class, "equals", new Class[] { null }));
904         assertNull(MethodUtils.getMethodObject(MutableObject.class, "equals", new Class[] { String.class, null, String.class }));
905     }
906 
907     /**
908      * Tests a {@code public} method.
909      */
910     @Test
911     @Annotated
912     public void testGetMethodsListWithAnnotation() throws NoSuchMethodException {
913         assertEquals(0, MethodUtils.getMethodsListWithAnnotation(Object.class, Annotated.class).size());
914         final List<Method> methodWithAnnotation = MethodUtils.getMethodsListWithAnnotation(MethodUtilsTest.class, Annotated.class);
915         assertEquals(2, methodWithAnnotation.size());
916         assertTrue(methodWithAnnotation.contains(MethodUtilsTest.class.getMethod("testGetMethodsWithAnnotation")));
917         assertTrue(methodWithAnnotation.contains(MethodUtilsTest.class.getMethod("testGetMethodsListWithAnnotation")));
918     }
919 
920     @Test
921     void testGetMethodsListWithAnnotationNullPointerException1() {
922         assertNullPointerException(() -> MethodUtils.getMethodsListWithAnnotation(FieldUtilsTest.class, null));
923     }
924 
925     @Test
926     void testGetMethodsListWithAnnotationNullPointerException2() {
927         assertNullPointerException(() -> MethodUtils.getMethodsListWithAnnotation(null, Annotated.class));
928     }
929 
930     @Test
931     void testGetMethodsListWithAnnotationNullPointerException3() {
932         assertNullPointerException(() -> MethodUtils.getMethodsListWithAnnotation(null, null));
933     }
934 
935     @Test
936     @Annotated
937     public void testGetMethodsWithAnnotation() throws NoSuchMethodException {
938         assertArrayEquals(new Method[0], MethodUtils.getMethodsWithAnnotation(Object.class, Annotated.class));
939         final Method[] methodsWithAnnotation = MethodUtils.getMethodsWithAnnotation(MethodUtilsTest.class, Annotated.class);
940         assertEquals(2, methodsWithAnnotation.length);
941         assertTrue(ArrayUtils.contains(methodsWithAnnotation, MethodUtilsTest.class.getMethod("testGetMethodsWithAnnotation")));
942         assertTrue(ArrayUtils.contains(methodsWithAnnotation, MethodUtilsTest.class.getMethod("testGetMethodsListWithAnnotation")));
943     }
944 
945     @Test
946     void testGetMethodsWithAnnotationIllegalArgumentException1() {
947         assertNullPointerException(() -> MethodUtils.getMethodsWithAnnotation(FieldUtilsTest.class, null));
948     }
949 
950     @Test
951     void testGetMethodsWithAnnotationIllegalArgumentException2() {
952         assertNullPointerException(() -> MethodUtils.getMethodsWithAnnotation(null, Annotated.class));
953     }
954 
955     @Test
956     void testGetMethodsWithAnnotationIllegalArgumentException3() {
957         assertNullPointerException(() -> MethodUtils.getMethodsWithAnnotation(null, null));
958     }
959 
960     @Test
961     void testGetMethodsWithAnnotationNotSearchSupersAndNotIgnoreAccess() {
962         assertArrayEquals(new Method[0], MethodUtils.getMethodsWithAnnotation(Object.class, Annotated.class, false, false));
963         final Method[] methodsWithAnnotation = MethodUtils.getMethodsWithAnnotation(PublicChild.class, Annotated.class, false, false);
964         assertEquals(1, methodsWithAnnotation.length);
965         assertEquals("PublicChild.publicAnnotatedMethod",
966                 methodsWithAnnotation[0].getDeclaringClass().getSimpleName() + '.' + methodsWithAnnotation[0].getName());
967     }
968 
969     @Test
970     void testGetMethodsWithAnnotationNotSearchSupersButIgnoreAccess() {
971         assertArrayEquals(new Method[0], MethodUtils.getMethodsWithAnnotation(Object.class, Annotated.class, false, true));
972         final Method[] methodsWithAnnotation = MethodUtils.getMethodsWithAnnotation(PublicChild.class, Annotated.class, false, true);
973         assertEquals(2, methodsWithAnnotation.length);
974         assertEquals("PublicChild", methodsWithAnnotation[0].getDeclaringClass().getSimpleName());
975         assertEquals("PublicChild", methodsWithAnnotation[1].getDeclaringClass().getSimpleName());
976         assertTrue(methodsWithAnnotation[0].getName().endsWith("AnnotatedMethod"));
977         assertTrue(methodsWithAnnotation[1].getName().endsWith("AnnotatedMethod"));
978     }
979 
980     @Test
981     void testGetMethodsWithAnnotationSearchSupersAndIgnoreAccess() {
982         assertArrayEquals(new Method[0], MethodUtils.getMethodsWithAnnotation(Object.class, Annotated.class, true, true));
983         final Method[] methodsWithAnnotation = MethodUtils.getMethodsWithAnnotation(PublicChild.class, Annotated.class, true, true);
984         assertEquals(4, methodsWithAnnotation.length);
985         assertEquals("PublicChild", methodsWithAnnotation[0].getDeclaringClass().getSimpleName());
986         assertEquals("PublicChild", methodsWithAnnotation[1].getDeclaringClass().getSimpleName());
987         assertTrue(methodsWithAnnotation[0].getName().endsWith("AnnotatedMethod"));
988         assertTrue(methodsWithAnnotation[1].getName().endsWith("AnnotatedMethod"));
989         assertEquals("Foo.doIt", methodsWithAnnotation[2].getDeclaringClass().getSimpleName() + '.' + methodsWithAnnotation[2].getName());
990         assertEquals("Parent.parentProtectedAnnotatedMethod",
991                 methodsWithAnnotation[3].getDeclaringClass().getSimpleName() + '.' + methodsWithAnnotation[3].getName());
992     }
993 
994     @Test
995     void testGetMethodsWithAnnotationSearchSupersButNotIgnoreAccess() {
996         assertArrayEquals(new Method[0], MethodUtils.getMethodsWithAnnotation(Object.class, Annotated.class, true, false));
997         final Method[] methodsWithAnnotation = MethodUtils.getMethodsWithAnnotation(PublicChild.class, Annotated.class, true, false);
998         assertEquals(2, methodsWithAnnotation.length);
999         assertEquals("PublicChild.publicAnnotatedMethod",
1000                 methodsWithAnnotation[0].getDeclaringClass().getSimpleName() + '.' + methodsWithAnnotation[0].getName());
1001         assertEquals("Foo.doIt", methodsWithAnnotation[1].getDeclaringClass().getSimpleName() + '.' + methodsWithAnnotation[1].getName());
1002     }
1003 
1004     @Test
1005     void testGetOverrideHierarchyExcludingInterfaces() {
1006         final Method method = MethodUtils.getAccessibleMethod(StringParameterizedChild.class, "consume", String.class);
1007         final Iterator<MethodDescriptor> expected =
1008                 Arrays.asList(new MethodDescriptor(StringParameterizedChild.class, "consume", String.class),
1009                         new MethodDescriptor(GenericParent.class, "consume", GenericParent.class.getTypeParameters()[0]))
1010                         .iterator();
1011         for (final Method m : MethodUtils.getOverrideHierarchy(method, Interfaces.EXCLUDE)) {
1012             assertTrue(expected.hasNext());
1013             final MethodDescriptor md = expected.next();
1014             assertEquals(md.declaringClass, m.getDeclaringClass());
1015             assertEquals(md.name, m.getName());
1016             assertEquals(md.parameterTypes.length, m.getParameterTypes().length);
1017             for (int i = 0; i < md.parameterTypes.length; i++) {
1018                 assertTrue(TypeUtils.equals(md.parameterTypes[i], m.getGenericParameterTypes()[i]));
1019             }
1020         }
1021         assertFalse(expected.hasNext());
1022     }
1023 
1024     @Test
1025     void testGetOverrideHierarchyIncludingInterfaces() {
1026         final Method method = MethodUtils.getAccessibleMethod(StringParameterizedChild.class, "consume", String.class);
1027         final Iterator<MethodDescriptor> expected =
1028                 Arrays.asList(new MethodDescriptor(StringParameterizedChild.class, "consume", String.class),
1029                         new MethodDescriptor(GenericParent.class, "consume", GenericParent.class.getTypeParameters()[0]),
1030                         new MethodDescriptor(GenericConsumer.class, "consume", GenericConsumer.class.getTypeParameters()[0]))
1031                         .iterator();
1032         for (final Method m : MethodUtils.getOverrideHierarchy(method, Interfaces.INCLUDE)) {
1033             assertTrue(expected.hasNext());
1034             final MethodDescriptor md = expected.next();
1035             assertEquals(md.declaringClass, m.getDeclaringClass());
1036             assertEquals(md.name, m.getName());
1037             assertEquals(md.parameterTypes.length, m.getParameterTypes().length);
1038             for (int i = 0; i < md.parameterTypes.length; i++) {
1039                 assertTrue(TypeUtils.equals(md.parameterTypes[i], m.getGenericParameterTypes()[i]));
1040             }
1041         }
1042         assertFalse(expected.hasNext());
1043     }
1044 
1045     @Test
1046     void testInvokeExactMethod() throws Exception {
1047         assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
1048         assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo"));
1049         assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", (Object[]) null));
1050         assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", null, null));
1051         assertEquals("foo(String)", MethodUtils.invokeExactMethod(testBean, "foo", ""));
1052         assertEquals("foo(Object)", MethodUtils.invokeExactMethod(testBean, "foo", new Object()));
1053         assertEquals("foo(Integer)", MethodUtils.invokeExactMethod(testBean, "foo", NumberUtils.INTEGER_ONE));
1054         assertEquals("foo(double)", MethodUtils.invokeExactMethod(testBean, "foo", new Object[] { NumberUtils.DOUBLE_ONE }, new Class[] { Double.TYPE }));
1055         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactMethod(testBean, "foo", NumberUtils.BYTE_ONE));
1056         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactMethod(testBean, "foo", NumberUtils.LONG_ONE));
1057         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactMethod(testBean, "foo", Boolean.TRUE));
1058         assertThrows(NullPointerException.class, () -> MethodUtils.invokeExactMethod(null, "foo", NumberUtils.BYTE_ONE));
1059         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactMethod(testBean, null, NumberUtils.BYTE_ONE));
1060         assertThrows(NullPointerException.class,
1061                 () -> MethodUtils.invokeExactMethod(null, "foo", new Object[] { NumberUtils.DOUBLE_ONE }, new Class[] { Double.TYPE }));
1062         assertThrows(NoSuchMethodException.class,
1063                 () -> MethodUtils.invokeExactMethod(testBean, null, new Object[] { NumberUtils.DOUBLE_ONE }, new Class[] { Double.TYPE }));
1064     }
1065 
1066     @Test
1067     void testInvokeExactStaticMethod() throws Exception {
1068         assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
1069         assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", (Object[]) null));
1070         assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", null, null));
1071         assertEquals("bar(String)", MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", ""));
1072         assertEquals("bar(Object)", MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", new Object()));
1073         assertEquals("bar(Integer)", MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", NumberUtils.INTEGER_ONE));
1074         assertEquals("bar(double)",
1075                 MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", new Object[] { NumberUtils.DOUBLE_ONE }, new Class[] { Double.TYPE }));
1076         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", NumberUtils.BYTE_ONE));
1077         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", NumberUtils.LONG_ONE));
1078         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", Boolean.TRUE));
1079     }
1080 
1081     @Test
1082     void testInvokeJavaVarArgsOverloadingResolution() throws Exception {
1083         // Primitive wrappers
1084         assertEquals("Byte...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", (byte) 1, (byte) 2));
1085         assertEquals("Short...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", (short) 1, (short) 2));
1086         assertEquals("Integer...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1, 2));
1087         assertEquals("Long...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1L, 2L));
1088         assertEquals("Float...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1f, 2f));
1089         assertEquals("Double...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1d, 2d));
1090         assertEquals("Boolean...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", true, false));
1091         // Number
1092         assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1, 1.1));
1093         assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1, 1L));
1094         assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1d, 1f));
1095         assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", (short) 1, (byte) 1));
1096         assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, "numOverload", ArrayUtils.EMPTY_OBJECT_ARRAY));
1097         assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, "numOverload", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
1098         assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, "numOverload", (Object[]) ArrayUtils.EMPTY_INTEGER_OBJECT_ARRAY));
1099         // Object
1100         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1, "s"));
1101         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1, true));
1102         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1.1, true));
1103         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 'c', true));
1104         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 1, 'c'));
1105         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 'c', "s"));
1106         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", ArrayUtils.EMPTY_OBJECT_ARRAY));
1107         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
1108         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", (Object[]) ArrayUtils.EMPTY_INTEGER_OBJECT_ARRAY));
1109         assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload"));
1110         // Other
1111         assertEquals("String...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", "a", "b"));
1112         assertEquals("Character...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", 'a', 'b'));
1113     }
1114 
1115     @Test
1116     void testInvokeMethod() throws Exception {
1117         assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
1118         assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo"));
1119         assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", (Object[]) null));
1120         assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", null, null));
1121         assertEquals("foo(String)", MethodUtils.invokeMethod(testBean, "foo", ""));
1122         assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo", new Object()));
1123         assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo", Boolean.TRUE));
1124         assertEquals("foo(Integer)", MethodUtils.invokeMethod(testBean, "foo", NumberUtils.INTEGER_ONE));
1125         assertEquals("foo(int)", MethodUtils.invokeMethod(testBean, "foo", NumberUtils.BYTE_ONE));
1126         assertEquals("foo(long)", MethodUtils.invokeMethod(testBean, "foo", NumberUtils.LONG_ONE));
1127         assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo", NumberUtils.DOUBLE_ONE));
1128         assertEquals("foo(String...)", MethodUtils.invokeMethod(testBean, "foo", "a", "b", "c"));
1129         assertEquals("foo(String...)", MethodUtils.invokeMethod(testBean, "foo", "a", "b", "c"));
1130         assertEquals("foo(int, String...)", MethodUtils.invokeMethod(testBean, "foo", 5, "a", "b", "c"));
1131         assertEquals("foo(long...)", MethodUtils.invokeMethod(testBean, "foo", 1L, 2L));
1132         assertEquals("foo(long...)", MethodUtils.invokeMethod(testBean, "foo", 1, 2));
1133         assertEquals("foo(long...)", MethodUtils.invokeMethod(testBean, "foo", (byte) 1, (byte) 2)); // widen
1134         assertEquals("foo(long...)", MethodUtils.invokeMethod(testBean, "foo", (short) 1, (short) 2)); // widen
1135         assertEquals("foo(long...)", MethodUtils.invokeMethod(testBean, "foo", (char) 1, (char) 2)); // widen
1136         TestBean.verify(new ImmutablePair<>("String...", new String[] { "x", "y" }), MethodUtils.invokeMethod(testBean, "varOverloadEcho", "x", "y"));
1137         TestBean.verify(new ImmutablePair<>("Number...", new Number[] { 17, 23, 42 }), MethodUtils.invokeMethod(testBean, "varOverloadEcho", 17, 23, 42));
1138         TestBean.verify(new ImmutablePair<>("String...", new String[] { "x", "y" }), MethodUtils.invokeMethod(testBean, "varOverloadEcho", "x", "y"));
1139         TestBean.verify(new ImmutablePair<>("Number...", new Number[] { 17, 23, 42 }), MethodUtils.invokeMethod(testBean, "varOverloadEcho", 17, 23, 42));
1140         assertNullPointerException(() -> MethodUtils.invokeMethod(null, "foo", 1, 2));
1141         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(testBean, null, 1, 2));
1142         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(new Object(), "nonExistent", new Object[] { "val" }, new Class<?>[] { null }));
1143     }
1144 
1145     @Test
1146     void testInvokeMethod_VarArgsWithNullValues() throws Exception {
1147         assertEquals("String...", MethodUtils.invokeMethod(testBean, "varOverload", "a", null, "c"));
1148         assertEquals("String...", MethodUtils.invokeMethod(testBean, "varOverload", "a", "b", null));
1149         assertEquals("String...", MethodUtils.invokeMethod(testBean, "varOverload", new String[] { "a" }, new Class<?>[] { String.class }));
1150         assertThrows(NoSuchMethodException.class,
1151                 () -> assertEquals("String...", MethodUtils.invokeMethod(testBean, "doesn't exist", new String[] { "a" }, new Class<?>[] { null })));
1152     }
1153 
1154     @Test
1155     void testInvokeMethod1PlusVarArgs() throws Exception {
1156         // intStringVarArg
1157         assertEquals("int, String...", MethodUtils.invokeMethod(testBean, "intStringVarArg", 1));
1158         assertEquals("int, String...", MethodUtils.invokeMethod(testBean, "intStringVarArg", 1, "s"));
1159         assertEquals("int, String...", MethodUtils.invokeMethod(testBean, "intStringVarArg", 1, "s1", "s2"));
1160         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(testBean, "intStringVarArg", 1, "s1", 5));
1161         // intLongVarArg
1162         assertEquals("int, long...", MethodUtils.invokeMethod(testBean, "intLongVarArg", 1));
1163         assertEquals("int, long...", MethodUtils.invokeMethod(testBean, "intLongVarArg", 1, 2L));
1164         assertEquals("int, long...", MethodUtils.invokeMethod(testBean, "intLongVarArg", 1, 2L, 3L));
1165         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(testBean, "intLongVarArg", 1, "s1", 5));
1166         // intIntVarArg
1167         assertEquals("int, int...", MethodUtils.invokeMethod(testBean, "intIntVarArg", 1));
1168         assertEquals("int, int...", MethodUtils.invokeMethod(testBean, "intIntVarArg", 1, 2));
1169         assertEquals("int, int...", MethodUtils.invokeMethod(testBean, "intIntVarArg", 1, 2, 3));
1170         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(testBean, "intLongVarArg", 1, "s1", 5));
1171     }
1172 
1173     @Test
1174     void testInvokeMethodForceAccessNoArgs() throws Exception {
1175         assertEquals("privateStringStuff()", MethodUtils.invokeMethod(testBean, true, "privateStringStuff"));
1176     }
1177 
1178     @Test
1179     void testInvokeMethodForceAccessWithArgs() throws Exception {
1180         assertEquals("privateStringStuff(Integer)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", 5));
1181         assertEquals("privateStringStuff(double)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", 5.0d));
1182         assertEquals("privateStringStuff(String)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", "Hi There"));
1183         assertEquals("privateStringStuff(Object)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", new Date()));
1184         assertNullPointerException(() -> MethodUtils.invokeMethod(null, true, "privateStringStuff", "Hi There"));
1185         assertNullPointerException(() -> MethodUtils.invokeMethod(testBean, true, null, "Hi There"));
1186     }
1187 
1188     @Test
1189     void testInvokeMethodIgnoresPrivateInterfaceMethod() throws Exception {
1190         // A private interface method needs Java 9, so the pair is precompiled under src/test/resources.
1191         assumeTrue(SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9));
1192         final Class<?> labels = Class.forName("org.apache.commons.lang3.reflect.testbed9.PrivateInterfaceLabels");
1193         final Object bean = labels.getMethod("newBean").invoke(null);
1194         assertEquals("bean", MethodUtils.invokeMethod(bean, "label"));
1195         assertNull(MethodUtils.getAccessibleMethod(bean.getClass(), "label"));
1196     }
1197 
1198     @Test
1199     void testInvokeMethodIgnoresStaticInterfaceMethod() throws Exception {
1200         assertSame(InstanceLabel.class, MethodUtils.getMatchingAccessibleMethod(InstanceLabel.class, "label").getDeclaringClass());
1201         assertEquals("instance", MethodUtils.invokeMethod(new InstanceLabel(), "label"));
1202         assertNull(MethodUtils.getAccessibleMethod(InstanceLabel.class, "label"));
1203     }
1204 
1205     @Test
1206     void testInvokeMethodOnNonPublicClass() throws Exception {
1207         assertEquals(0, MethodUtils.invokeMethod(Collections.emptyList(), "size"));
1208         assertEquals(2, MethodUtils.invokeMethod(Arrays.asList(1, 2), "size"));
1209         assertEquals(0, MethodUtils.invokeMethod(Collections.emptyMap(), "size"));
1210         assertEquals(0, MethodUtils.invokeMethod(Collections.unmodifiableList(new ArrayList<>()), "size"));
1211         assertNull(MethodUtils.invokeMethod(new TestMutable(), "getValue"));
1212     }
1213 
1214     @Test
1215     void testInvokeMethodVarArgsNotUniqueResolvable() throws Exception {
1216         assertEquals("Boolean...", MethodUtils.invokeMethod(testBean, "varOverload", new Object[] { null }));
1217         assertEquals("Object...", MethodUtils.invokeMethod(testBean, "varOverload", (Object[]) null));
1218     }
1219 
1220     @Test
1221     void testInvokeMethodVarArgsOfInterface() throws Exception {
1222         // packagePrivateEmptyInterface
1223         assertEquals("PackagePrivateEmptyInterface...", MethodUtils.invokeMethod(testBean, "packagePrivateEmptyInterface",
1224                 new PublicImpl1OfPackagePrivateEmptyInterface(), new PublicImpl2OfPackagePrivateEmptyInterface()));
1225         assertEquals("PackagePrivateEmptyInterface...", MethodUtils.invokeMethod(testBean, "packagePrivateEmptyInterface", new PackagePrivateEmptyInterface() {
1226             // empty
1227         }, new PackagePrivateEmptyInterface() {
1228             // empty
1229         }));
1230     }
1231 
1232     @Test
1233     void testInvokeMethodVarArgsUnboxingBooleanArray() throws Exception {
1234         final TestBean testBean = new TestBean();
1235         final boolean[] actual = (boolean[]) MethodUtils.invokeMethod(testBean, "unboxing", Boolean.TRUE, Boolean.FALSE);
1236         assertArrayEquals(new boolean[] { true, false }, actual);
1237         assertTrue(testBean.unboxBooleanArray);
1238     }
1239 
1240     @Test
1241     void testInvokeMethodVarArgsUnboxingByteArray() throws Exception {
1242         final TestBean testBean = new TestBean();
1243         final byte[] actual = (byte[]) MethodUtils.invokeMethod(testBean, "unboxing", Byte.valueOf((byte) 1), Byte.valueOf((byte) 2));
1244         assertArrayEquals(new byte[] { 1, 2 }, actual);
1245         assertTrue(testBean.unboxByteArray);
1246     }
1247 
1248     @Test
1249     void testInvokeMethodVarArgsUnboxingCharArray() throws Exception {
1250         final TestBean testBean = new TestBean();
1251         final char[] actual = (char[]) MethodUtils.invokeMethod(testBean, "unboxing", Character.valueOf((char) 1), Character.valueOf((char) 2));
1252         assertArrayEquals(new char[] { 1, 2 }, actual);
1253         assertTrue(testBean.unboxCharArray);
1254     }
1255 
1256     @Test
1257     void testInvokeMethodVarArgsUnboxingDoubleArray() throws Exception {
1258         final TestBean testBean = new TestBean();
1259         final double[] actual = (double[]) MethodUtils.invokeMethod(testBean, "unboxing", Double.valueOf(1), Double.valueOf(2));
1260         assertArrayEquals(new double[] { 1, 2 }, actual);
1261         assertTrue(testBean.unboxDoubleArray);
1262     }
1263 
1264     @Test
1265     void testInvokeMethodVarArgsUnboxingFloatArray() throws Exception {
1266         final TestBean testBean = new TestBean();
1267         final float[] actual = (float[]) MethodUtils.invokeMethod(testBean, "unboxing", Float.valueOf(1), Float.valueOf(2));
1268         assertArrayEquals(new float[] { 1, 2 }, actual);
1269         assertTrue(testBean.unboxFloatArray);
1270     }
1271 
1272     @Test
1273     void testInvokeMethodVarArgsUnboxingIntArray() throws Exception {
1274         final TestBean testBean = new TestBean();
1275         final int[] actual = (int[]) MethodUtils.invokeMethod(testBean, "unboxing", Integer.valueOf(1), Integer.valueOf(2));
1276         assertArrayEquals(new int[] { 1, 2 }, actual);
1277         assertTrue(testBean.unboxIntArray);
1278     }
1279 
1280     @Test
1281     void testInvokeMethodVarArgsUnboxingLongArray() throws Exception {
1282         final TestBean testBean = new TestBean();
1283         final long[] actual = (long[]) MethodUtils.invokeMethod(testBean, "unboxing", Long.valueOf(1), Long.valueOf(2));
1284         assertArrayEquals(new long[] { 1, 2 }, actual);
1285         assertTrue(testBean.unboxLongArray);
1286     }
1287 
1288     @Test
1289     void testInvokeMethodVarArgsUnboxingShortArray() throws Exception {
1290         final TestBean testBean = new TestBean();
1291         final short[] actual = (short[]) MethodUtils.invokeMethod(testBean, "unboxing", Short.valueOf((short) 1), Short.valueOf((short) 2));
1292         assertArrayEquals(new short[] { 1, 2 }, actual);
1293         assertTrue(testBean.unboxShortArray);
1294     }
1295 
1296     @Test
1297     void testInvokeStaticMethod() throws Exception {
1298         assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, "bar"));
1299         assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, "bar", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
1300         assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, "bar", (Object[]) null));
1301         assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, "bar", null, null));
1302         assertEquals("bar(String)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", ""));
1303         assertEquals("bar(Object)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", new Object()));
1304         assertEquals("bar(Object)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", Boolean.TRUE));
1305         assertEquals("bar(Integer)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", NumberUtils.INTEGER_ONE));
1306         assertEquals("bar(int)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", NumberUtils.BYTE_ONE));
1307         assertEquals("static int", MethodUtils.invokeStaticMethod(TestBean.class, "staticInt", NumberUtils.BYTE_ONE));
1308         assertEquals("static int", MethodUtils.invokeStaticMethod(TestBean.class, "staticInt", NumberUtils.SHORT_ONE));
1309         assertEquals("static int", MethodUtils.invokeStaticMethod(TestBean.class, "staticInt", NumberUtils.INTEGER_ONE));
1310         assertEquals("static int", MethodUtils.invokeStaticMethod(TestBean.class, "staticInt", 'a'));
1311         assertEquals("bar(double)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", NumberUtils.DOUBLE_ONE));
1312         assertEquals("bar(String...)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", "a", "b"));
1313         assertEquals("bar(long...)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", 1L, 2L));
1314         assertEquals("bar(long...)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", (byte) 1, (byte) 2)); // widen
1315         assertEquals("bar(long...)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", (short) 1, (short) 2)); // widen
1316         assertEquals("bar(long...)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", 1, 2)); // widen
1317         assertEquals("bar(Integer, String...)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", NumberUtils.INTEGER_ONE, "a", "b"));
1318         // You cannot widen a Short to an Integer in Java source, but you can a short to an int but this API declares an Integer, not an int.
1319         assertThrows(NoSuchMethodException.class,
1320                 () -> assertEquals("bar(Integer, String...)", MethodUtils.invokeStaticMethod(TestBean.class, "bar", NumberUtils.SHORT_ONE, "a", "b"))); // widen
1321         TestBean.verify(new ImmutablePair<>("String...", new String[] { "x", "y" }),
1322                 MethodUtils.invokeStaticMethod(TestBean.class, "varOverloadEchoStatic", "x", "y"));
1323         TestBean.verify(new ImmutablePair<>("Number...", new Number[] { 17, 23, 42 }),
1324                 MethodUtils.invokeStaticMethod(TestBean.class, "varOverloadEchoStatic", 17, 23, 42));
1325         TestBean.verify(new ImmutablePair<>("String...", new String[] { "x", "y" }),
1326                 MethodUtils.invokeStaticMethod(TestBean.class, "varOverloadEchoStatic", "x", "y"));
1327         TestBean.verify(new ImmutablePair<>("Number...", new Number[] { 17, 23, 42 }),
1328                 MethodUtils.invokeStaticMethod(TestBean.class, "varOverloadEchoStatic", 17, 23, 42));
1329         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeStaticMethod(TestBean.class, "does_not_exist"));
1330     }
1331 
1332     @Test
1333     void testInvokeStaticMethod1PlusVarArgs() throws Exception {
1334         // staticIntStringVarArg
1335         assertEquals("static int, String...", MethodUtils.invokeStaticMethod(TestBean.class, "staticIntStringVarArg", 1));
1336         assertEquals("static int, String...", MethodUtils.invokeStaticMethod(TestBean.class, "staticIntStringVarArg", 1, "s"));
1337         assertEquals("static int, String...", MethodUtils.invokeStaticMethod(TestBean.class, "staticIntStringVarArg", 1, "s1", "s2"));
1338         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeStaticMethod(TestBean.class, "staticIntStringVarArg", 1, "s1", 5));
1339         // staticIntLongVarArg
1340         assertEquals("static int, long...", MethodUtils.invokeMethod(testBean, "staticIntLongVarArg", 1));
1341         assertEquals("static int, long...", MethodUtils.invokeMethod(testBean, "staticIntLongVarArg", 1, 2L));
1342         assertEquals("static int, long...", MethodUtils.invokeMethod(testBean, "staticIntLongVarArg", 1, 2L, 3L));
1343         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(testBean, "staticIntLongVarArg", 1, "s1", 5));
1344         // staticIntIntVarArg
1345         assertEquals("static int, int...", MethodUtils.invokeMethod(testBean, "staticIntIntVarArg", 1));
1346         assertEquals("static int, int...", MethodUtils.invokeMethod(testBean, "staticIntIntVarArg", 1, 2));
1347         assertEquals("static int, int...", MethodUtils.invokeMethod(testBean, "staticIntIntVarArg", 1, 2, 3));
1348         assertThrows(NoSuchMethodException.class, () -> MethodUtils.invokeMethod(testBean, "staticIntIntVarArg", 1, "s1", 5));
1349     }
1350 
1351     @Test
1352     void testInvokeStaticMethodOnNonPublicSubclass() throws Exception {
1353         // A static method hides rather than overrides, so the subclass's own declaration is invoked.
1354         assertSame(StaticChild.class, MethodUtils.getMatchingAccessibleMethod(StaticChild.class, "who").getDeclaringClass());
1355         assertEquals("child", MethodUtils.invokeStaticMethod(StaticChild.class, "who"));
1356     }
1357 
1358     @Test
1359     void testInvokeStaticMethodVarArgsOfInterface() throws Exception {
1360         // staticPackagePrivateEmptyInterface
1361         assertEquals("static PackagePrivateEmptyInterface...", MethodUtils.invokeStaticMethod(TestBean.class, "staticPackagePrivateEmptyInterface",
1362                 new PublicImpl1OfPackagePrivateEmptyInterface(), new PublicImpl2OfPackagePrivateEmptyInterface()));
1363         assertEquals("static PackagePrivateEmptyInterface...",
1364                 MethodUtils.invokeStaticMethod(TestBean.class, "staticPackagePrivateEmptyInterface", new PackagePrivateEmptyInterface() {
1365                     // empty
1366                 }, new PackagePrivateEmptyInterface() {
1367                     // empty
1368                 }));
1369     }
1370 
1371     @Test
1372     void testNullArgument() {
1373         expectMatchingAccessibleMethodParameterTypes(TestBean.class, "oneParameter", singletonArray(null), singletonArray(String.class));
1374     }
1375 
1376     @Test
1377     void testVarargsOverloadingResolution() {
1378         // This code is not a test of MethodUtils.
1379         // Rather it makes explicit the behavior of the Java specification for
1380         // various cases of overload resolution.
1381         assertEquals("Byte...", TestBean.varOverload((byte) 1, (byte) 2));
1382         assertEquals("Short...", TestBean.varOverload((short) 1, (short) 2));
1383         assertEquals("Integer...", TestBean.varOverload(1, 2));
1384         assertEquals("Long...", TestBean.varOverload(1L, 2L));
1385         assertEquals("Float...", TestBean.varOverload(1f, 2f));
1386         assertEquals("Double...", TestBean.varOverload(1d, 2d));
1387         assertEquals("Character...", TestBean.varOverload('a', 'b'));
1388         assertEquals("String...", TestBean.varOverload("a", "b"));
1389         assertEquals("Boolean...", TestBean.varOverload(true, false));
1390         assertEquals("Object...", TestBean.varOverload(1, "s"));
1391         assertEquals("Object...", TestBean.varOverload(1, true));
1392         assertEquals("Object...", TestBean.varOverload(1.1, true));
1393         assertEquals("Object...", TestBean.varOverload('c', true));
1394         assertEquals("Number...", TestBean.varOverload(1, 1.1));
1395         assertEquals("Number...", TestBean.varOverload(1, 1L));
1396         assertEquals("Number...", TestBean.varOverload(1d, 1f));
1397         assertEquals("Number...", TestBean.varOverload((short) 1, (byte) 1));
1398         assertEquals("Object...", TestBean.varOverload(1, 'c'));
1399         assertEquals("Object...", TestBean.varOverload('c', "s"));
1400     }
1401 
1402     private String toString(final Class<?>[] c) {
1403         return Arrays.asList(c).toString();
1404     }
1405 }