1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.commons.reflect;
18
19 import static java.lang.annotation.ElementType.*;
20 import static java.lang.annotation.RetentionPolicy.*;
21 import static org.apache.juneau.commons.utils.CollectionUtils.*;
22 import static org.junit.jupiter.api.Assertions.*;
23
24 import java.lang.annotation.*;
25 import java.lang.reflect.*;
26 import java.util.*;
27 import java.util.function.*;
28 import java.util.stream.*;
29
30 import org.apache.juneau.*;
31 import org.junit.jupiter.api.*;
32
33 class MethodInfo_Test extends TestBase {
34
35 @Documented
36 @Target({METHOD,TYPE})
37 @Retention(RUNTIME)
38 @Inherited
39 public static @interface A {
40 String value();
41 }
42
43 @Documented
44 @Target({METHOD,TYPE})
45 @Retention(RUNTIME)
46 @Inherited
47 public static @interface AX {
48 String value();
49 }
50
51 @Target({METHOD,TYPE})
52 @Retention(RUNTIME)
53 public static @interface TestAnnotationWithDefault {
54 String value() default "defaultValue";
55 }
56
57 private static void check(String expected, Object o) {
58 assertEquals(expected, TO_STRING.apply(o));
59 }
60
61 private static final Function<Object,String> TO_STRING = new Function<>() {
62 @Override
63 public String apply(Object t) {
64 if (t == null)
65 return null;
66 if (t instanceof MethodInfo t2)
67 return t2.getDeclaringClass().getNameSimple() + '.' + ((MethodInfo)t).getShortName();
68 if (t instanceof Method t2)
69 return t2.getDeclaringClass().getSimpleName() + '.' + MethodInfo.of((Method)t).getShortName();
70 if (t instanceof List<?> t2)
71 return (t2.stream().map(this).collect(Collectors.joining(",")));
72 if (t instanceof AnnotationInfo t2)
73 return apply(t2.inner());
74 if (t instanceof A t2)
75 return "@A(" + t2.value() + ")";
76 if (t instanceof ClassInfo t2)
77 return t2.getNameSimple();
78 return t.toString();
79 }
80 };
81
82 private static MethodInfo ofm(Class<?> c, String name, Class<?>...pt) {
83 try {
84 return MethodInfo.of(c.getDeclaredMethod(name, pt));
85 } catch (NoSuchMethodException | SecurityException e) {
86 fail(e.getLocalizedMessage());
87 }
88 return null;
89 }
90
91
92
93
94
95 public static class A1 {
96 public void m() {}
97 }
98 static MethodInfo a_m = ofm(A1.class, "m");
99
100 public static class EqualsTestClass {
101 public void method1() {}
102 public void method2(String param) {}
103 }
104
105 public interface B1 {
106 int foo(int x);
107 int foo(String x);
108 int foo();
109 }
110 public static class B2 {
111 public int foo(int x) { return 0; }
112 public int foo(String x) {return 0;}
113 public int foo() {return 0;}
114 }
115 public static class B3 extends B2 implements B1 {
116 @Override public int foo(int x) {return 0;}
117 @Override public int foo(String x) {return 0;}
118 @Override public int foo() {return 0;}
119 }
120
121 public interface BM1 {
122 void foo(String s);
123 }
124
125 public interface BM2 {
126 void foo(String s);
127 }
128
129 public class BM3 {
130 public void foo(String s) {}
131 }
132
133 public interface BM4 extends BM1 {
134 @Override void foo(String s);
135 }
136
137 public class BM5 extends BM3 implements BM2 {
138 @Override public void foo(String s) {}
139 }
140
141 public class BM6 extends BM5 implements BM4 {
142 @Override public void foo(String s) {}
143 }
144
145 public interface BM7 {
146 void bar();
147 }
148
149 public class BM8 implements BM7 {
150 @Override public void bar() {}
151 public void baz() {}
152 }
153
154 @A("C1")
155 public interface C1 {
156 @A("a1") void a1();
157 @A("a2a") void a2();
158 @A("a3") void a3(CharSequence foo);
159 void a4();
160 void a5();
161 }
162
163 @A("C2")
164 public static class C2 implements C1 {
165 @Override public void a1() {}
166 @Override @A("a2b") public void a2() {}
167 @Override public void a3(CharSequence s) {}
168 @Override public void a4() {}
169 @Override public void a5() {}
170 }
171
172 @A("C3")
173 public static class C3 extends C2 {
174 @Override public void a1() {}
175 @Override public void a2() {}
176 @Override public void a3(CharSequence foo) {}
177 @Override @A("a4") public void a4() {}
178 @Override public void a5() {}
179 }
180 static MethodInfo
181 c_a1 = ofm(C3.class, "a1"),
182 c_a2 = ofm(C3.class, "a2"),
183 c_a3 = ofm(C3.class, "a3", CharSequence.class),
184 c_a4 = ofm(C3.class, "a4"),
185 c_a5 = ofm(C3.class, "a5");
186
187 public static class D {
188 public void a1() {}
189 public Integer a2() {return null;}
190 }
191 static MethodInfo
192 d_a1 = ofm(D.class, "a1"),
193 d_a2 = ofm(D.class, "a2");
194
195 public static class E {
196 private String f;
197 public void a1(CharSequence foo) {
198 f = foo == null ? null : foo.toString();
199 }
200 public void a2(int f1, int f2) {}
201 public void a3() {}
202 }
203 static MethodInfo
204 e_a1 = ofm(E.class, "a1", CharSequence.class),
205 e_a2 = ofm(E.class, "a2", int.class, int.class),
206 e_a3 = ofm(E.class, "a3");
207
208 public static class F {
209 public void isA() {}
210 public void is() {}
211 public void getA() {}
212 public void get() {}
213 public void setA() {}
214 public void set() {}
215 public void foo() {}
216 }
217 static MethodInfo
218 f_isA = ofm(F.class, "isA"),
219 f_is = ofm(F.class, "is"),
220 f_getA = ofm(F.class, "getA"),
221 f_get = ofm(F.class, "get"),
222 f_setA = ofm(F.class, "setA"),
223 f_set = ofm(F.class, "set"),
224 f_foo = ofm(F.class, "foo");
225
226 public static class G {
227 public void a1() {}
228 public void a1(int a1) {}
229 public void a1(int a1, int a2) {}
230 public void a1(String a1) {}
231 public void a2() {}
232 public void a3() {}
233 }
234 static MethodInfo
235 g_a1a = ofm(G.class, "a1"),
236 g_a1b = ofm(G.class, "a1", int.class),
237 g_a1c = ofm(G.class, "a1", int.class, int.class),
238 g_a1d = ofm(G.class, "a1", String.class),
239 g_a2 = ofm(G.class, "a2"),
240 g_a3 = ofm(G.class, "a3");
241
242 public interface DefaultInterface {
243 default String defaultMethod() { return "default"; }
244 }
245
246
247
248 public interface GenericInterface<T> {
249 T getValue();
250 }
251 public static class BridgeTestClass implements GenericInterface<String> {
252 @Override
253 public String getValue() { return "value"; }
254 }
255
256
257
258
259 @Test
260 void a001_accessible() {
261 var result = a_m.accessible();
262 assertSame(a_m, result);
263 }
264
265
266
267
268 @Test
269 void a002_compareTo() {
270 var s = new TreeSet<>(l(g_a1a, g_a1b, g_a1c, g_a1d, g_a2, g_a3));
271 check("[a1(), a1(int), a1(String), a1(int,int), a2(), a3()]", s);
272 }
273
274
275
276
277 @Test
278 void a003_getAnnotatedReturnType() {
279 var annotatedType = d_a2.getAnnotatedReturnType();
280 assertNotNull(annotatedType);
281 assertEquals(Integer.class, annotatedType.getType());
282 }
283
284
285
286
287 @Test
288 void a004_getAnnotatableType() {
289 assertEquals(AnnotatableType.METHOD_TYPE, a_m.getAnnotatableType());
290 }
291
292
293
294
295 @Test
296 void a005_getAnnotations() {
297
298 var annotations = c_a1.getAnnotations();
299 assertNotNull(annotations);
300 assertTrue(annotations.size() > 0);
301
302
303 var aAnnotations = annotations.stream().filter(a -> a.isType(A.class)).toList();
304 assertTrue(aAnnotations.size() >= 1);
305 }
306
307
308
309
310 @Test
311 void a006_getAnnotations_typed() {
312
313 var aAnnotations = c_a1.getAnnotations(A.class).toList();
314 assertTrue(aAnnotations.size() >= 1);
315
316
317 var axAnnotations = c_a1.getAnnotations(AX.class).toList();
318 assertEquals(0, axAnnotations.size());
319 }
320
321
322
323
324 @Test
325 void a007_getDefaultValue() {
326
327 assertNull(a_m.getDefaultValue());
328
329
330 var annotationMethod = ClassInfo.of(A.class).getPublicMethod(m -> m.hasName("value")).get();
331 assertNull(annotationMethod.getDefaultValue());
332
333
334 var annotationWithDefault = ClassInfo.of(TestAnnotationWithDefault.class).getPublicMethod(m -> m.hasName("value")).get();
335 assertNotNull(annotationWithDefault.getDefaultValue());
336 assertEquals("defaultValue", annotationWithDefault.getDefaultValue());
337 }
338
339
340
341
342 @Test
343 void a008_getGenericReturnType() {
344 var genericType = d_a2.getGenericReturnType();
345 assertNotNull(genericType);
346 assertEquals(Integer.class, genericType);
347 }
348
349
350
351
352 @Test
353 void a009_getLabel() {
354 var label = a_m.getLabel();
355 assertNotNull(label);
356 assertTrue(label.contains("A1"));
357 assertTrue(label.contains("m()"));
358 }
359
360
361
362
363 @Test
364 void a010_getMatchingMethods() throws Exception {
365
366 var mi = MethodInfo.of(B3.class.getMethod("foo", int.class));
367 check("B3.foo(int),B1.foo(int),B2.foo(int)", mi.getMatchingMethods());
368
369
370 var mi2 = MethodInfo.of(BM5.class.getMethod("foo", String.class));
371 check("BM5.foo(String),BM2.foo(String),BM3.foo(String)", mi2.getMatchingMethods());
372
373
374 var mi3 = MethodInfo.of(BM6.class.getMethod("foo", String.class));
375 check("BM6.foo(String),BM4.foo(String),BM1.foo(String),BM5.foo(String),BM2.foo(String),BM3.foo(String)", mi3.getMatchingMethods());
376
377
378 var mi4 = MethodInfo.of(Object.class.getMethod("toString"));
379 check("Object.toString()", mi4.getMatchingMethods());
380
381
382 var mi5 = MethodInfo.of(BM8.class.getMethod("bar"));
383 check("BM8.bar(),BM7.bar()", mi5.getMatchingMethods());
384
385
386 var mi6 = MethodInfo.of(BM8.class.getMethod("baz"));
387 check("BM8.baz()", mi6.getMatchingMethods());
388 }
389
390
391
392
393 @Test
394 void a011_getName() {
395 assertEquals("m", a_m.getName());
396 assertEquals("a1", e_a1.getName());
397 }
398
399
400
401
402 @Test
403 void a012_getPropertyName() {
404 assertEquals("a", f_isA.getPropertyName());
405 assertEquals("is", f_is.getPropertyName());
406 assertEquals("a", f_getA.getPropertyName());
407 assertEquals("get", f_get.getPropertyName());
408 assertEquals("a", f_setA.getPropertyName());
409 assertEquals("set", f_set.getPropertyName());
410 assertEquals("foo", f_foo.getPropertyName());
411 }
412
413
414
415
416 @Test
417 void a013_getReturnType() {
418 check("void", d_a1.getReturnType());
419 check("Integer", d_a2.getReturnType());
420 }
421
422
423
424
425 @Test
426 void a014_getSignature() {
427 assertEquals("a1(java.lang.CharSequence)", e_a1.getSignature());
428 assertEquals("a2(int,int)", e_a2.getSignature());
429 assertEquals("a3", e_a3.getSignature());
430 }
431
432
433
434
435 @Test
436 void a015_hasAllParameters() {
437 assertTrue(e_a2.hasAllParameters(int.class));
438 assertTrue(e_a2.hasAllParameters(int.class, int.class));
439 assertFalse(e_a2.hasAllParameters(int.class, String.class));
440 }
441
442
443
444
445 @Test
446 void a016_hasAnnotation() {
447
448 assertTrue(c_a1.hasAnnotation(A.class));
449 assertFalse(c_a1.hasAnnotation(AX.class));
450 }
451
452
453
454
455 @Test
456 void a017_hasOnlyParameterTypes() {
457 assertTrue(e_a1.hasOnlyParameterTypes(CharSequence.class));
458 assertTrue(e_a1.hasOnlyParameterTypes(CharSequence.class, Map.class));
459 assertFalse(e_a1.hasOnlyParameterTypes());
460
461
462
463
464
465 var result = e_a2.hasOnlyParameterTypes(int.class);
466
467 assertNotNull(result);
468 }
469
470
471
472
473 @Test
474 void a018_hasParameter() {
475 assertTrue(e_a2.hasParameter(int.class));
476 assertFalse(e_a2.hasParameter(String.class));
477 }
478
479
480
481
482 @Test
483 void a019_hasReturnType_class() {
484 assertTrue(d_a1.hasReturnType(void.class));
485 assertFalse(d_a1.hasReturnType(Integer.class));
486 assertTrue(d_a2.hasReturnType(Integer.class));
487 assertFalse(d_a2.hasReturnType(Number.class));
488 }
489
490
491
492
493 @Test
494 void a020_hasReturnType_classInfo() {
495 var voidClass = ClassInfo.of(void.class);
496 var integerClass = ClassInfo.of(Integer.class);
497 assertTrue(d_a1.hasReturnType(voidClass));
498 assertFalse(d_a1.hasReturnType(integerClass));
499 assertTrue(d_a2.hasReturnType(integerClass));
500 }
501
502
503
504
505 @Test
506 void a021_hasReturnTypeParent_class() {
507 assertTrue(d_a1.hasReturnTypeParent(void.class));
508 assertFalse(d_a1.hasReturnTypeParent(Integer.class));
509 assertTrue(d_a2.hasReturnTypeParent(Integer.class));
510 assertTrue(d_a2.hasReturnTypeParent(Number.class));
511 }
512
513
514
515
516 @Test
517 void a022_hasReturnTypeParent_classInfo() {
518 var integerClass = ClassInfo.of(Integer.class);
519 var numberClass = ClassInfo.of(Number.class);
520 assertTrue(d_a2.hasReturnTypeParent(integerClass));
521 assertTrue(d_a2.hasReturnTypeParent(numberClass));
522 }
523
524
525
526
527 @Test
528 void a023_inner() {
529 var method = a_m.inner();
530 assertNotNull(method);
531 assertEquals("m", method.getName());
532 }
533
534
535
536
537 @Test
538 void a024_invoke() throws Exception {
539 var e = new E();
540 e_a1.invoke(e, "foo");
541 assertEquals("foo", e.f);
542 e_a1.invoke(e, (CharSequence)null);
543 assertNull(e.f);
544 }
545
546
547
548
549 @Test
550 void a025_invokeLenient() throws Exception {
551 var e = new E();
552 e_a1.invokeLenient(e, "foo", 123);
553 assertEquals("foo", e.f);
554 e_a1.invokeLenient(e, 123, "bar");
555 assertEquals("bar", e.f);
556 }
557
558
559
560
561 @Test
562 void a026_is() {
563
564 assertFalse(f_foo.is(ElementFlag.BRIDGE));
565 assertTrue(f_foo.is(ElementFlag.NOT_BRIDGE));
566
567
568
569
570
571 ClassInfo bridgeClass = ClassInfo.of(BridgeTestClass.class);
572 var bridgeMethods = bridgeClass.getPublicMethods();
573 var bridgeMethod = bridgeMethods.stream()
574 .filter(m -> m.isBridge())
575 .findFirst();
576 if (bridgeMethod.isPresent()) {
577
578 assertTrue(bridgeMethod.get().is(ElementFlag.BRIDGE));
579 assertFalse(bridgeMethod.get().is(ElementFlag.NOT_BRIDGE));
580 } else {
581
582 ClassInfo listClass = ClassInfo.of(java.util.ArrayList.class);
583 var methods = listClass.getPublicMethods();
584 var arrayListBridge = methods.stream()
585 .filter(m -> m.isBridge())
586 .findFirst();
587 if (arrayListBridge.isPresent()) {
588 assertTrue(arrayListBridge.get().is(ElementFlag.BRIDGE));
589 assertFalse(arrayListBridge.get().is(ElementFlag.NOT_BRIDGE));
590 }
591 }
592
593
594 var defaultMethod = ClassInfo.of(DefaultInterface.class).getPublicMethod(m -> m.hasName("defaultMethod")).get();
595 assertTrue(defaultMethod.is(ElementFlag.DEFAULT));
596 assertFalse(defaultMethod.is(ElementFlag.NOT_DEFAULT));
597
598
599 assertFalse(a_m.is(ElementFlag.DEFAULT));
600 assertTrue(a_m.is(ElementFlag.NOT_DEFAULT));
601 }
602
603
604
605
606 @Test
607 void a027_isAll() {
608 assertTrue(a_m.isAll(ElementFlag.NOT_BRIDGE, ElementFlag.NOT_DEFAULT));
609 assertFalse(a_m.isAll(ElementFlag.BRIDGE, ElementFlag.DEFAULT));
610 }
611
612
613
614
615 @Test
616 void a028_isAny() {
617 assertTrue(a_m.isAny(ElementFlag.NOT_BRIDGE, ElementFlag.DEFAULT));
618 assertFalse(a_m.isAny(ElementFlag.BRIDGE, ElementFlag.DEFAULT));
619 }
620
621
622
623
624 @Test
625 void a029_isBridge() {
626 assertFalse(f_foo.isBridge());
627 }
628
629
630
631
632 @Test
633 void a030_isDefault() {
634 var defaultMethod = ClassInfo.of(DefaultInterface.class).getPublicMethod(m -> m.hasName("defaultMethod")).get();
635 assertTrue(defaultMethod.isDefault());
636 assertFalse(a_m.isDefault());
637 }
638
639
640
641
642 @Test
643 void a031_matches() throws Exception {
644 var mi1 = MethodInfo.of(B3.class.getMethod("foo", int.class));
645 var mi2 = MethodInfo.of(B2.class.getMethod("foo", int.class));
646 var mi3 = MethodInfo.of(B3.class.getMethod("foo", String.class));
647
648 assertTrue(mi1.matches(mi2));
649 assertFalse(mi1.matches(mi3));
650 }
651
652
653
654
655 @Test
656 void a032_of_withClass() throws Exception {
657 var method = A1.class.getMethod("m");
658 var mi = MethodInfo.of(A1.class, method);
659 check("A1.m()", mi);
660 }
661
662
663
664
665 @Test
666 void a033_of_withClassInfo() {
667 check("A1.m()", MethodInfo.of(ClassInfo.of(A1.class), a_m.inner()));
668 }
669
670
671
672
673 @Test
674 void a034_of_withoutClass() {
675 var mi = MethodInfo.of(a_m.inner());
676 check("A1.m()", mi);
677
678
679 assertThrows(IllegalArgumentException.class, () -> MethodInfo.of((Method)null));
680 assertThrows(IllegalArgumentException.class, () -> MethodInfo.of((ClassInfo)null, null));
681 }
682
683
684
685
686 @Test
687 void a035_getDeclaringClass() throws Exception {
688 check("A1", a_m.getDeclaringClass());
689 check("B3", MethodInfo.of(B3.class.getMethod("foo", int.class)).getDeclaringClass());
690 }
691
692
693
694
695 @Test
696 void a036_getFullName() {
697 var fullName = e_a1.getFullName();
698 assertNotNull(fullName);
699 assertTrue(fullName.contains("MethodInfo_Test$E"));
700 assertTrue(fullName.contains("a1"));
701 assertTrue(fullName.contains("CharSequence"));
702 }
703
704
705
706
707 @Test
708 void a037_getParameters() {
709 assertEquals(0, e_a3.getParameters().size());
710 assertEquals(1, e_a1.getParameters().size());
711 assertEquals(2, e_a2.getParameters().size());
712
713
714 int[] count = {0};
715 e_a2.getParameters().stream().filter(x -> true).forEach(x -> count[0]++);
716 assertEquals(2, count[0]);
717 }
718
719
720
721
722 @Test
723 void a038_getShortName() {
724 assertEquals("m()", a_m.getShortName());
725 assertEquals("a1(CharSequence)", e_a1.getShortName());
726 assertEquals("a2(int,int)", e_a2.getShortName());
727 }
728
729
730
731
732 @Test
733 void a039_getSimpleName() {
734 assertEquals("m", a_m.getSimpleName());
735 assertEquals("a1", e_a1.getSimpleName());
736 }
737
738
739
740
741 @Test
742 void a040_isConstructor() {
743 assertFalse(a_m.isConstructor());
744 assertTrue(ClassInfo.of(A1.class).getPublicConstructor(cons -> cons.getParameterCount() == 0).get().isConstructor());
745 }
746
747
748
749
750 @Test
751 void a041_equals_hashCode() throws Exception {
752
753 Method m1 = EqualsTestClass.class.getMethod("method1");
754 MethodInfo mi1a = MethodInfo.of(m1);
755 MethodInfo mi1b = MethodInfo.of(m1);
756
757 Method m2 = EqualsTestClass.class.getMethod("method2", String.class);
758 MethodInfo mi2 = MethodInfo.of(m2);
759
760
761 assertEquals(mi1a, mi1b);
762 assertEquals(mi1a.hashCode(), mi1b.hashCode());
763
764
765 assertNotEquals(mi1a, mi2);
766 assertNotEquals(mi1a, null);
767 assertNotEquals(mi1a, "not a MethodInfo");
768
769
770 assertEquals(mi1a, mi1a);
771
772
773 assertEquals(mi1a, mi1b);
774 assertEquals(mi1b, mi1a);
775
776
777 MethodInfo mi1c = MethodInfo.of(m1);
778 assertEquals(mi1a, mi1b);
779 assertEquals(mi1b, mi1c);
780 assertEquals(mi1a, mi1c);
781
782
783 Map<MethodInfo, String> map = new HashMap<>();
784 map.put(mi1a, "value1");
785 assertEquals("value1", map.get(mi1b));
786 assertEquals("value1", map.get(mi1c));
787
788
789 map.put(mi2, "value2");
790 assertEquals("value2", map.get(mi2));
791 assertNotEquals("value2", map.get(mi1a));
792
793
794 Set<MethodInfo> set = new HashSet<>();
795 set.add(mi1a);
796 assertTrue(set.contains(mi1b));
797 assertTrue(set.contains(mi1c));
798 assertFalse(set.contains(mi2));
799 }
800 }
801