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.reflect.AnnotationTraversal.*;
22 import static org.junit.jupiter.api.Assertions.*;
23
24 import java.lang.annotation.*;
25 import org.apache.juneau.*;
26 import org.apache.juneau.commons.collections.*;
27 import org.junit.jupiter.api.*;
28
29 class AnnotationProvider_Test extends TestBase {
30
31
32
33
34
35 @Target(TYPE)
36 @Retention(RUNTIME)
37 public static @interface TestAnnotation {
38 String value() default "default";
39 }
40
41 @Target({TYPE, METHOD, FIELD, CONSTRUCTOR, PARAMETER})
42 @Retention(RUNTIME)
43 public static @interface MultiTargetAnnotation {
44 int value() default 0;
45 }
46
47 @Target(TYPE)
48 @Retention(RUNTIME)
49 public static @interface ParentAnnotation {
50 String value() default "";
51 }
52
53 @TestAnnotation("class")
54 public static class TestClass {
55 @MultiTargetAnnotation(1)
56 public String field1;
57
58 @MultiTargetAnnotation(2)
59 public TestClass() {}
60
61 @MultiTargetAnnotation(3)
62 public void method1() {}
63
64 public void method2(@MultiTargetAnnotation(4) String param) {}
65 }
66
67 @ParentAnnotation("parent")
68 public static class ParentClass {}
69
70 @TestAnnotation("child")
71 public static class ChildClass extends ParentClass {}
72
73
74 public static interface MatchingMethodInterface {
75 @MultiTargetAnnotation(10)
76 void matchingMethod(String param);
77 }
78
79 public static class MatchingMethodParent {
80 @MultiTargetAnnotation(20)
81 public void matchingMethod(String param) {}
82 }
83
84 public static class MatchingMethodChild extends MatchingMethodParent implements MatchingMethodInterface {
85 @MultiTargetAnnotation(30)
86 @Override
87 public void matchingMethod(String param) {}
88 }
89
90
91 public static interface MatchingParameterInterface {
92 void matchingParameterMethod(@MultiTargetAnnotation(100) String param);
93 }
94
95 public static class MatchingParameterParent {
96 public void matchingParameterMethod(@MultiTargetAnnotation(200) String param) {}
97 }
98
99 public static class MatchingParameterChild extends MatchingParameterParent implements MatchingParameterInterface {
100 @Override
101 public void matchingParameterMethod(@MultiTargetAnnotation(300) String param) {}
102 }
103
104
105
106
107
108 @Test
109 void a01_create_returnsBuilder() {
110 var builder = AnnotationProvider.create();
111 assertNotNull(builder);
112 var provider = builder.build();
113 assertNotNull(provider);
114 }
115
116 @Test
117 void a02_instance_isNotNull() {
118 assertNotNull(AnnotationProvider.INSTANCE);
119 }
120
121
122
123
124
125 @Test
126 void b01_find_typedClass_returnsAnnotations() {
127 var provider = AnnotationProvider.create().build();
128 var ci = ClassInfo.of(TestClass.class);
129 var annotations = provider.find(TestAnnotation.class, ci, SELF);
130
131 assertNotNull(annotations);
132 assertEquals(1, annotations.size());
133 assertEquals("class", annotations.get(0).getValue().orElse(null));
134 }
135
136 @Test
137 void b02_find_typedClass_withParents_returnsAnnotationsFromHierarchy() {
138 var provider = AnnotationProvider.create().build();
139 var ci = ClassInfo.of(ChildClass.class);
140 var annotations = provider.find(TestAnnotation.class, ci, SELF, PARENTS);
141
142 assertNotNull(annotations);
143
144 assertTrue(annotations.size() >= 1);
145 var childAnnotation = annotations.stream()
146 .filter(a -> a.getValue().orElse("").equals("child"))
147 .findFirst();
148 assertTrue(childAnnotation.isPresent());
149 }
150
151 @Test
152 void b03_find_typedClass_notFound_returnsEmptyList() {
153 var provider = AnnotationProvider.create().build();
154 var ci = ClassInfo.of(TestClass.class);
155 var annotations = provider.find(ParentAnnotation.class, ci, SELF);
156
157 assertNotNull(annotations);
158 assertTrue(annotations.isEmpty());
159 }
160
161 @Test
162 void b04_find_typedClass_withNullType_throwsException() {
163 var provider = AnnotationProvider.create().build();
164 var ci = ClassInfo.of(TestClass.class);
165 assertThrows(IllegalArgumentException.class, () -> provider.find(null, ci, SELF));
166 }
167
168 @Test
169 void b05_find_typedClass_withNullClassInfo_throwsException() {
170 var provider = AnnotationProvider.create().build();
171 ClassInfo nullClassInfo = null;
172 assertThrows(IllegalArgumentException.class, () -> provider.find(TestAnnotation.class, nullClassInfo, SELF));
173 }
174
175
176
177
178
179 @Test
180 void c01_find_untypedClass_returnsAllAnnotations() {
181 var provider = AnnotationProvider.create().build();
182 var ci = ClassInfo.of(TestClass.class);
183 var annotations = provider.find(ci, SELF);
184
185 assertNotNull(annotations);
186 assertTrue(annotations.size() >= 1);
187 assertTrue(annotations.stream().anyMatch(a -> a.isType(TestAnnotation.class)));
188 }
189
190 @Test
191 void c02_find_untypedClass_withNullClassInfo_throwsException() {
192 var provider = AnnotationProvider.create().build();
193 assertThrows(IllegalArgumentException.class, () -> provider.find((ClassInfo)null, SELF));
194 }
195
196
197
198
199
200 @Test
201 void d01_find_typedField_returnsAnnotations() {
202 var provider = AnnotationProvider.create().build();
203 var ci = ClassInfo.of(TestClass.class);
204 var field = ci.getPublicField(x -> x.hasName("field1")).orElse(null);
205 assertNotNull(field);
206
207 var annotations = provider.find(MultiTargetAnnotation.class, field, SELF);
208
209 assertNotNull(annotations);
210 assertEquals(1, annotations.size());
211 assertEquals(1, annotations.get(0).getInt("value").orElse(0));
212 }
213
214 @Test
215 void d03_find_typedField_withRuntimeAnnotations_includesRuntimeAndDeclared() {
216
217 var runtimeAnnotation = new RuntimeOnAnnotation(new String[]{"org.apache.juneau.commons.reflect.AnnotationProvider_Test$TestClass.field1"}, "runtimeField");
218 var provider = AnnotationProvider.create()
219 .addRuntimeAnnotations(runtimeAnnotation)
220 .build();
221 var ci = ClassInfo.of(TestClass.class);
222 var field = ci.getPublicField(x -> x.hasName("field1")).orElse(null);
223 assertNotNull(field);
224
225
226 var annotations = provider.find(TestAnnotation.class, field, SELF);
227
228 assertNotNull(annotations);
229
230 assertTrue(annotations.size() >= 1, "Should find at least the runtime annotation");
231
232
233 var runtimeAnnotationFound = annotations.stream()
234 .filter(a -> a.getValue().orElse("").equals("runtimeField"))
235 .findFirst();
236 assertTrue(runtimeAnnotationFound.isPresent(), "Should find runtime annotation on field");
237 }
238
239 @Test
240 void d02_find_typedField_notFound_returnsEmptyList() {
241 var provider = AnnotationProvider.create().build();
242 var ci = ClassInfo.of(TestClass.class);
243 var field = ci.getPublicField(x -> x.hasName("field1")).orElse(null);
244 assertNotNull(field);
245
246 var annotations = provider.find(TestAnnotation.class, field, SELF);
247
248 assertNotNull(annotations);
249 assertTrue(annotations.isEmpty());
250 }
251
252
253
254
255
256 @Test
257 void e01_find_untypedField_returnsAllAnnotations() {
258 var provider = AnnotationProvider.create().build();
259 var ci = ClassInfo.of(TestClass.class);
260 var field = ci.getPublicField(x -> x.hasName("field1")).orElse(null);
261 assertNotNull(field);
262
263 var annotations = provider.find(field, SELF);
264
265 assertNotNull(annotations);
266 assertTrue(annotations.size() >= 1);
267 assertTrue(annotations.stream().anyMatch(a -> a.isType(MultiTargetAnnotation.class)));
268 }
269
270
271
272
273
274 @Test
275 void f01_find_typedConstructor_returnsAnnotations() {
276 var provider = AnnotationProvider.create().build();
277 var ci = ClassInfo.of(TestClass.class);
278 var constructor = ci.getPublicConstructor(x -> x.getParameterCount() == 0).orElse(null);
279 assertNotNull(constructor);
280
281 var annotations = provider.find(MultiTargetAnnotation.class, constructor, SELF);
282
283 assertNotNull(annotations);
284 assertEquals(1, annotations.size());
285 assertEquals(2, annotations.get(0).getInt("value").orElse(0));
286 }
287
288
289
290
291
292 @Test
293 void g01_find_untypedConstructor_returnsAllAnnotations() {
294 var provider = AnnotationProvider.create().build();
295 var ci = ClassInfo.of(TestClass.class);
296 var constructor = ci.getPublicConstructor(x -> x.getParameterCount() == 0).orElse(null);
297 assertNotNull(constructor);
298
299 var annotations = provider.find(constructor, SELF);
300
301 assertNotNull(annotations);
302 assertTrue(annotations.size() >= 1);
303 assertTrue(annotations.stream().anyMatch(a -> a.isType(MultiTargetAnnotation.class)));
304 }
305
306
307
308
309
310 @Test
311 void h01_find_typedMethod_returnsAnnotations() {
312 var provider = AnnotationProvider.create().build();
313 var ci = ClassInfo.of(TestClass.class);
314 MethodInfo method = ci.getPublicMethod(x -> x.hasName("method1")).orElse(null);
315 assertNotNull(method);
316
317 var annotations = provider.find(MultiTargetAnnotation.class, method, SELF);
318
319 assertNotNull(annotations);
320 assertEquals(1, annotations.size());
321 assertEquals(3, annotations.get(0).getInt("value").orElse(0));
322 }
323
324
325
326
327
328 @Test
329 void i01_find_untypedMethod_returnsAllAnnotations() {
330 var provider = AnnotationProvider.create().build();
331 var ci = ClassInfo.of(TestClass.class);
332 var method = ci.getPublicMethod(x -> x.hasName("method1")).orElse(null);
333 assertNotNull(method);
334
335 var annotations = provider.find(method, SELF);
336
337 assertNotNull(annotations);
338 assertTrue(annotations.size() >= 1);
339 assertTrue(annotations.stream().anyMatch(a -> a.isType(MultiTargetAnnotation.class)));
340 }
341
342
343
344
345
346 @Test
347 void j01_find_typedParameter_returnsAnnotations() {
348 var provider = AnnotationProvider.create().build();
349 var ci = ClassInfo.of(TestClass.class);
350 var method = ci.getPublicMethod(x -> x.hasName("method2")).orElse(null);
351 assertNotNull(method);
352 ParameterInfo param = method.getParameter(0);
353 assertNotNull(param);
354
355 var annotations = provider.find(MultiTargetAnnotation.class, param, SELF);
356
357 assertNotNull(annotations);
358 assertEquals(1, annotations.size());
359 assertEquals(4, annotations.get(0).getInt("value").orElse(0));
360 }
361
362
363
364
365
366 @Test
367 void k01_find_untypedParameter_returnsAllAnnotations() {
368 var provider = AnnotationProvider.create().build();
369 var ci = ClassInfo.of(TestClass.class);
370 var method = ci.getPublicMethod(x -> x.hasName("method2")).orElse(null);
371 assertNotNull(method);
372 var param = method.getParameter(0);
373 assertNotNull(param);
374
375 var annotations = provider.find(param, SELF);
376
377 assertNotNull(annotations);
378 assertTrue(annotations.size() >= 1);
379 assertTrue(annotations.stream().anyMatch(a -> a.isType(MultiTargetAnnotation.class)));
380 }
381
382
383
384
385
386 @Test
387 void l01_has_typedClass_exists_returnsTrue() {
388 var provider = AnnotationProvider.create().build();
389 var ci = ClassInfo.of(TestClass.class);
390
391 assertTrue(provider.has(TestAnnotation.class, ci, SELF));
392 }
393
394 @Test
395 void l02_has_typedClass_notExists_returnsFalse() {
396 var provider = AnnotationProvider.create().build();
397 var ci = ClassInfo.of(TestClass.class);
398
399 assertFalse(provider.has(ParentAnnotation.class, ci, SELF));
400 }
401
402
403
404
405
406 @Test
407 void l03_has_typedConstructor_exists_returnsTrue() {
408 var provider = AnnotationProvider.create().build();
409 var ci = ClassInfo.of(TestClass.class);
410 ConstructorInfo constructor = ci.getPublicConstructor(x -> x.getParameterCount() == 0).orElse(null);
411 assertNotNull(constructor);
412
413 assertTrue(provider.has(MultiTargetAnnotation.class, constructor, SELF));
414 }
415
416 @Test
417 void l04_has_typedConstructor_notExists_returnsFalse() {
418 var provider = AnnotationProvider.create().build();
419 var ci = ClassInfo.of(TestClass.class);
420 ConstructorInfo constructor = ci.getPublicConstructor(x -> x.getParameterCount() == 0).orElse(null);
421 assertNotNull(constructor);
422
423 assertFalse(provider.has(TestAnnotation.class, constructor, SELF));
424 }
425
426
427
428
429
430 @Test
431 void l05_has_typedField_exists_returnsTrue() {
432 var provider = AnnotationProvider.create().build();
433 var ci = ClassInfo.of(TestClass.class);
434 FieldInfo field = ci.getPublicField(x -> x.hasName("field1")).orElse(null);
435 assertNotNull(field);
436
437 assertTrue(provider.has(MultiTargetAnnotation.class, field, SELF));
438 }
439
440 @Test
441 void l06_has_typedField_notExists_returnsFalse() {
442 var provider = AnnotationProvider.create().build();
443 var ci = ClassInfo.of(TestClass.class);
444 FieldInfo field = ci.getPublicField(x -> x.hasName("field1")).orElse(null);
445 assertNotNull(field);
446
447 assertFalse(provider.has(TestAnnotation.class, field, SELF));
448 }
449
450
451
452
453
454 @Test
455 void l07_has_typedMethod_exists_returnsTrue() {
456 var provider = AnnotationProvider.create().build();
457 var ci = ClassInfo.of(TestClass.class);
458 MethodInfo method = ci.getPublicMethod(x -> x.hasName("method1")).orElse(null);
459 assertNotNull(method);
460
461 assertTrue(provider.has(MultiTargetAnnotation.class, method, SELF));
462 }
463
464 @Test
465 void l08_has_typedMethod_notExists_returnsFalse() {
466 var provider = AnnotationProvider.create().build();
467 var ci = ClassInfo.of(TestClass.class);
468 MethodInfo method = ci.getPublicMethod(x -> x.hasName("method1")).orElse(null);
469 assertNotNull(method);
470
471 assertFalse(provider.has(TestAnnotation.class, method, SELF));
472 }
473
474
475
476
477
478 @Test
479 void l09_has_typedParameter_exists_returnsTrue() {
480 var provider = AnnotationProvider.create().build();
481 var ci = ClassInfo.of(TestClass.class);
482 var method = ci.getPublicMethod(x -> x.hasName("method2")).orElse(null);
483 assertNotNull(method);
484 ParameterInfo param = method.getParameter(0);
485 assertNotNull(param);
486
487 assertTrue(provider.has(MultiTargetAnnotation.class, param, SELF));
488 }
489
490 @Test
491 void l10_has_typedParameter_notExists_returnsFalse() {
492 var provider = AnnotationProvider.create().build();
493 var ci = ClassInfo.of(TestClass.class);
494 var method = ci.getPublicMethod(x -> x.hasName("method2")).orElse(null);
495 assertNotNull(method);
496 ParameterInfo param = method.getParameter(0);
497 assertNotNull(param);
498
499 assertFalse(provider.has(TestAnnotation.class, param, SELF));
500 }
501
502
503
504
505
506 @Test
507 void l11_find_typedClass_noTraversals_usesDefaultTraversals() {
508
509 var provider = AnnotationProvider.create().build();
510 var ci = ClassInfo.of(ChildClass.class);
511
512
513 var annotations = provider.find(TestAnnotation.class, ci);
514
515 assertNotNull(annotations);
516
517 assertTrue(annotations.size() >= 1);
518 }
519
520 @Test
521 void l12_find_typedMethod_noTraversals_usesDefaultTraversals() {
522
523 var provider = AnnotationProvider.create().build();
524 var ci = ClassInfo.of(TestClass.class);
525 MethodInfo method = ci.getPublicMethod(x -> x.hasName("method1")).orElse(null);
526 assertNotNull(method);
527
528
529 var annotations = provider.find(MultiTargetAnnotation.class, method);
530
531 assertNotNull(annotations);
532 assertTrue(annotations.size() >= 1);
533 }
534
535 @Test
536 void l13_find_typedField_noTraversals_usesDefaultTraversals() {
537
538 var provider = AnnotationProvider.create().build();
539 var ci = ClassInfo.of(TestClass.class);
540 FieldInfo field = ci.getPublicField(x -> x.hasName("field1")).orElse(null);
541 assertNotNull(field);
542
543
544 var annotations = provider.find(MultiTargetAnnotation.class, field);
545
546 assertNotNull(annotations);
547 assertEquals(1, annotations.size());
548 }
549
550 @Test
551 void l14_find_typedConstructor_noTraversals_usesDefaultTraversals() {
552
553 var provider = AnnotationProvider.create().build();
554 var ci = ClassInfo.of(TestClass.class);
555 ConstructorInfo constructor = ci.getPublicConstructor(x -> x.getParameterCount() == 0).orElse(null);
556 assertNotNull(constructor);
557
558
559 var annotations = provider.find(MultiTargetAnnotation.class, constructor);
560
561 assertNotNull(annotations);
562 assertEquals(1, annotations.size());
563 }
564
565 @Test
566 void l15_find_typedParameter_noTraversals_usesDefaultTraversals() {
567
568 var provider = AnnotationProvider.create().build();
569 var ci = ClassInfo.of(TestClass.class);
570 var method = ci.getPublicMethod(x -> x.hasName("method2")).orElse(null);
571 assertNotNull(method);
572 ParameterInfo param = method.getParameter(0);
573 assertNotNull(param);
574
575
576 var annotations = provider.find(MultiTargetAnnotation.class, param);
577
578 assertNotNull(annotations);
579 assertTrue(annotations.size() >= 1);
580 }
581
582 @Test
583 void l16_find_typedClass_withPackageTraversal_nullPackage_handlesGracefully() {
584
585
586 var provider = AnnotationProvider.create().build();
587
588
589 var ci = ClassInfo.of(int.class);
590 assertNull(ci.getPackage(), "int.class should have no package");
591
592
593 var annotations = provider.find(TestAnnotation.class, ci, AnnotationTraversal.PACKAGE);
594
595
596 assertNotNull(annotations);
597 assertEquals(0, annotations.size());
598 }
599
600 @Test
601 void l17_find_typedMethod_withMatchingMethodsTraversal_includesParentAndInterfaceMethods() {
602
603 var provider = AnnotationProvider.create().build();
604 var ci = ClassInfo.of(MatchingMethodChild.class);
605 MethodInfo method = ci.getPublicMethod(x -> x.hasName("matchingMethod")).orElse(null);
606 assertNotNull(method);
607
608
609 var matchingMethods = method.getMatchingMethods();
610 assertTrue(matchingMethods.size() >= 3, "Should have at least child, interface, and parent methods. Found: " + matchingMethods.size());
611
612
613 var parentMethod = matchingMethods.stream()
614 .filter(m -> MatchingMethodParent.class.equals(m.getDeclaringClass().inner()))
615 .findFirst();
616 assertTrue(parentMethod.isPresent(), "Parent method should be in matching methods");
617
618
619 var parentMethodAnnotations = parentMethod.get().getDeclaredAnnotations(MultiTargetAnnotation.class).toList();
620 assertTrue(parentMethodAnnotations.size() > 0, "Parent method should have annotation. Found " + parentMethodAnnotations.size() + " annotations");
621 var parentMethodAnnotation = parentMethodAnnotations.get(0);
622
623 var parentAnnotationValue = parentMethodAnnotation.getInt("value").orElse(null);
624 if (parentAnnotationValue == null) {
625 parentAnnotationValue = parentMethodAnnotation.getValue(Integer.class, "value").orElse(null);
626 }
627 assertEquals(20, parentAnnotationValue, "Parent method annotation should have value 20. Annotation: " + parentMethodAnnotation);
628
629
630 var methodsAfterSkip = matchingMethods.stream().skip(1).toList();
631 assertTrue(methodsAfterSkip.size() >= 2, "Should have interface and parent methods after skipping child");
632
633
634
635 var annotations = provider.find(MultiTargetAnnotation.class, method, MATCHING_METHODS);
636
637 assertNotNull(annotations);
638
639
640
641
642 assertTrue(annotations.size() >= 2, "Should find annotations from parent and interface matching methods. Found: " + annotations.size());
643
644
645 var foundValues = annotations.stream()
646 .map(a -> {
647 Integer val = a.getInt("value").orElse(null);
648 if (val == null) {
649 val = a.getValue(Integer.class, "value").orElse(null);
650 }
651 return val;
652 })
653 .filter(v -> v != null)
654 .toList();
655
656
657 var interfaceAnnotation = annotations.stream()
658 .filter(a -> {
659 Integer val = a.getInt("value").orElse(null);
660 if (val == null) {
661 val = a.getValue(Integer.class, "value").orElse(null);
662 }
663 return val != null && val.intValue() == 10;
664 })
665 .findFirst();
666 assertTrue(interfaceAnnotation.isPresent(), "Should find annotation from interface method. Found values: " + foundValues);
667
668
669 var parentAnnotation = annotations.stream()
670 .filter(a -> {
671 Integer val = a.getInt("value").orElse(null);
672 if (val == null) {
673 val = a.getValue(Integer.class, "value").orElse(null);
674 }
675 return val != null && val.intValue() == 20;
676 })
677 .findFirst();
678 assertTrue(parentAnnotation.isPresent(), "Should find annotation from parent class method. Found values: " + foundValues + ", matching methods count: " + matchingMethods.size());
679 }
680
681 @Test
682 void l18_find_typedParameter_withMatchingParametersTraversal_includesParentAndInterfaceParameters() {
683
684 var provider = AnnotationProvider.create().build();
685 var ci = ClassInfo.of(MatchingParameterChild.class);
686 MethodInfo method = ci.getPublicMethod(x -> x.hasName("matchingParameterMethod")).orElse(null);
687 assertNotNull(method);
688 ParameterInfo param = method.getParameter(0);
689 assertNotNull(param);
690
691
692 var matchingParameters = param.getMatchingParameters();
693 assertTrue(matchingParameters.size() >= 3, "Should have at least child, interface, and parent parameters. Found: " + matchingParameters.size());
694
695
696 var parentParameter = matchingParameters.stream()
697 .filter(p -> {
698 var paramMethod = p.getMethod();
699 if (paramMethod != null) {
700 return MatchingParameterParent.class.equals(paramMethod.getDeclaringClass().inner());
701 }
702 return false;
703 })
704 .findFirst();
705 assertTrue(parentParameter.isPresent(), "Parent parameter should be in matching parameters");
706
707
708 var parentParameterAnnotations = parentParameter.get().getAnnotations(MultiTargetAnnotation.class).toList();
709 assertTrue(parentParameterAnnotations.size() > 0, "Parent parameter should have annotation. Found " + parentParameterAnnotations.size() + " annotations");
710 var parentParameterAnnotation = parentParameterAnnotations.get(0);
711 var parentParameterValue = parentParameterAnnotation.getInt("value").orElse(null);
712 if (parentParameterValue == null) {
713 parentParameterValue = parentParameterAnnotation.getValue(Integer.class, "value").orElse(null);
714 }
715 assertEquals(200, parentParameterValue, "Parent parameter annotation should have value 200. Annotation: " + parentParameterAnnotation);
716
717
718 var parametersAfterSkip = matchingParameters.stream().skip(1).toList();
719 assertTrue(parametersAfterSkip.size() >= 2, "Should have interface and parent parameters after skipping child");
720
721
722
723 var annotations = provider.find(MultiTargetAnnotation.class, param, MATCHING_PARAMETERS);
724
725 assertNotNull(annotations);
726
727
728
729
730 assertTrue(annotations.size() >= 2, "Should find annotations from parent and interface matching parameters. Found: " + annotations.size());
731
732
733 var foundValues = annotations.stream()
734 .map(a -> {
735 Integer val = a.getInt("value").orElse(null);
736 if (val == null) {
737 val = a.getValue(Integer.class, "value").orElse(null);
738 }
739 return val;
740 })
741 .filter(v -> v != null)
742 .toList();
743
744
745 var interfaceAnnotation = annotations.stream()
746 .filter(a -> {
747 Integer val = a.getInt("value").orElse(null);
748 if (val == null) {
749 val = a.getValue(Integer.class, "value").orElse(null);
750 }
751 return val != null && val.intValue() == 100;
752 })
753 .findFirst();
754 assertTrue(interfaceAnnotation.isPresent(), "Should find annotation from interface parameter. Found values: " + foundValues);
755
756
757 var parentAnnotation = annotations.stream()
758 .filter(a -> {
759 Integer val = a.getInt("value").orElse(null);
760 if (val == null) {
761 val = a.getValue(Integer.class, "value").orElse(null);
762 }
763 return val != null && val.intValue() == 200;
764 })
765 .findFirst();
766 assertTrue(parentAnnotation.isPresent(), "Should find annotation from parent class parameter. Found values: " + foundValues + ", matching parameters count: " + matchingParameters.size());
767 }
768
769 @Test
770 void l19_find_typedMethod_withRuntimeAnnotation_loadsFromAnnotationMap() {
771
772 var runtimeAnnotation = new RuntimeOnAnnotation(new String[]{"org.apache.juneau.commons.reflect.AnnotationProvider_Test$TestClass.method1"}, "runtimeMethod");
773 var provider = AnnotationProvider.create()
774 .addRuntimeAnnotations(runtimeAnnotation)
775 .build();
776 var ci = ClassInfo.of(TestClass.class);
777 MethodInfo method = ci.getPublicMethod(x -> x.hasName("method1")).orElse(null);
778 assertNotNull(method);
779
780
781
782 var annotations = provider.find(TestAnnotation.class, method, SELF);
783
784 assertNotNull(annotations);
785
786 assertTrue(annotations.size() >= 1, "Should find at least the runtime annotation");
787
788
789 var runtimeAnnotationFound = annotations.stream()
790 .filter(a -> a.getValue().orElse("").equals("runtimeMethod"))
791 .findFirst();
792 assertTrue(runtimeAnnotationFound.isPresent(), "Should find runtime annotation on method");
793 }
794
795 @Test
796 void l20_find_typedConstructor_withRuntimeAnnotation_loadsFromAnnotationMap() {
797
798
799 var runtimeAnnotation = new RuntimeOnAnnotation(new String[]{"org.apache.juneau.commons.reflect.AnnotationProvider_Test$TestClass()"}, "runtimeConstructor");
800 var provider = AnnotationProvider.create()
801 .addRuntimeAnnotations(runtimeAnnotation)
802 .build();
803 var ci = ClassInfo.of(TestClass.class);
804 ConstructorInfo constructor = ci.getPublicConstructor(x -> x.getParameterCount() == 0).orElse(null);
805 assertNotNull(constructor);
806
807
808
809 var annotations = provider.find(TestAnnotation.class, constructor, SELF);
810
811 assertNotNull(annotations);
812
813 assertTrue(annotations.size() >= 1, "Should find at least the runtime annotation");
814
815
816 var runtimeAnnotationFound = annotations.stream()
817 .filter(a -> a.getValue().orElse("").equals("runtimeConstructor"))
818 .findFirst();
819 assertTrue(runtimeAnnotationFound.isPresent(), "Should find runtime annotation on constructor");
820 }
821
822
823
824
825
826 @Test
827 void m01_builder_cacheMode_buildsProvider() {
828 var provider = AnnotationProvider.create()
829 .cacheMode(CacheMode.NONE)
830 .build();
831 assertNotNull(provider);
832 }
833
834 @Test
835 void m02_builder_logOnExit_buildsProvider() {
836 var provider = AnnotationProvider.create()
837 .logOnExit()
838 .build();
839 assertNotNull(provider);
840 }
841
842 @Test
843 void m03_builder_logOnExit_withBoolean_coversLine402() {
844
845 var provider1 = AnnotationProvider.create()
846 .logOnExit(true)
847 .build();
848 assertNotNull(provider1);
849
850 var provider2 = AnnotationProvider.create()
851 .logOnExit(false)
852 .build();
853 assertNotNull(provider2);
854 }
855
856 @Test
857 void m04_builder_chaining_buildsProvider() {
858 var provider = AnnotationProvider.create()
859 .cacheMode(CacheMode.NONE)
860 .logOnExit()
861 .build();
862 assertNotNull(provider);
863 }
864
865
866
867
868
869
870 private static class RuntimeTestAnnotation implements TestAnnotation {
871 private final Class<?>[] onClass;
872 private final String value;
873
874 RuntimeTestAnnotation(Class<?>[] onClass, String value) {
875 this.onClass = onClass;
876 this.value = value;
877 }
878
879 @Override
880 public String value() {
881 return value;
882 }
883
884 @Override
885 public Class<? extends Annotation> annotationType() {
886 return TestAnnotation.class;
887 }
888
889 @SuppressWarnings("unused")
890 public Class<?>[] onClass() {
891 return onClass;
892 }
893
894 @Override
895 public boolean equals(Object obj) {
896 if (!(obj instanceof TestAnnotation))
897 return false;
898 TestAnnotation other = (TestAnnotation)obj;
899 return value.equals(other.value());
900 }
901
902 @Override
903 public int hashCode() {
904 return value.hashCode();
905 }
906
907 @Override
908 public String toString() {
909 return "@TestAnnotation(value=" + value + ")";
910 }
911 }
912
913
914 private static class RuntimeOnAnnotation implements TestAnnotation {
915 private final String[] on;
916 private final String value;
917
918 RuntimeOnAnnotation(String[] on, String value) {
919 this.on = on;
920 this.value = value;
921 }
922
923 @Override
924 public String value() {
925 return value;
926 }
927
928 @Override
929 public Class<? extends Annotation> annotationType() {
930 return TestAnnotation.class;
931 }
932
933 @SuppressWarnings("unused")
934 public String[] on() {
935 return on;
936 }
937
938 @Override
939 public boolean equals(Object obj) {
940 if (!(obj instanceof TestAnnotation))
941 return false;
942 TestAnnotation other = (TestAnnotation)obj;
943 return value.equals(other.value());
944 }
945
946 @Override
947 public int hashCode() {
948 return value.hashCode();
949 }
950
951 @Override
952 public String toString() {
953 return "@TestAnnotation(value=" + value + ")";
954 }
955 }
956
957 @Test
958 void n01_addRuntimeAnnotations_varargs_callsListVersion() {
959
960 var runtimeAnnotation1 = new RuntimeTestAnnotation(new Class<?>[]{TestClass.class}, "runtime1");
961 var runtimeAnnotation2 = new RuntimeTestAnnotation(new Class<?>[]{ParentClass.class}, "runtime2");
962
963 var provider = AnnotationProvider.create()
964 .addRuntimeAnnotations(runtimeAnnotation1, runtimeAnnotation2)
965 .build();
966
967 assertNotNull(provider);
968
969
970 var ci = ClassInfo.of(TestClass.class);
971 var annotations = provider.find(TestAnnotation.class, ci, SELF);
972
973
974 assertTrue(annotations.size() >= 1);
975 var runtimeAnnotation = annotations.stream()
976 .filter(a -> a.getValue().orElse("").equals("runtime1"))
977 .findFirst();
978 assertTrue(runtimeAnnotation.isPresent());
979 }
980
981 @Test
982 void n04_addRuntimeAnnotations_withOnMethod_coversLine343() {
983
984 var className = TestClass.class.getName();
985 var runtimeAnnotation = new RuntimeOnAnnotation(new String[]{className}, "runtimeOn");
986
987 var provider = AnnotationProvider.create()
988 .addRuntimeAnnotations(runtimeAnnotation)
989 .build();
990
991 assertNotNull(provider);
992
993
994 var ci = ClassInfo.of(TestClass.class);
995 var annotations = provider.find(TestAnnotation.class, ci, SELF);
996
997
998 assertTrue(annotations.size() >= 1);
999 var runtimeAnnotationFound = annotations.stream()
1000 .filter(a -> a.getValue().orElse("").equals("runtimeOn"))
1001 .findFirst();
1002 assertTrue(runtimeAnnotationFound.isPresent());
1003 }
1004
1005
1006 private static class InvalidOnClassAnnotation implements TestAnnotation {
1007 @Override
1008 public String value() {
1009 return "invalid";
1010 }
1011
1012 @Override
1013 public Class<? extends Annotation> annotationType() {
1014 return TestAnnotation.class;
1015 }
1016
1017 @SuppressWarnings("unused")
1018 public String onClass() {
1019 return "invalid";
1020 }
1021
1022 @Override
1023 public boolean equals(Object obj) {
1024 return obj instanceof TestAnnotation;
1025 }
1026
1027 @Override
1028 public int hashCode() {
1029 return 0;
1030 }
1031
1032 @Override
1033 public String toString() {
1034 return "@TestAnnotation";
1035 }
1036 }
1037
1038
1039 private static class InvalidOnAnnotation implements TestAnnotation {
1040 @Override
1041 public String value() {
1042 return "invalid";
1043 }
1044
1045 @Override
1046 public Class<? extends Annotation> annotationType() {
1047 return TestAnnotation.class;
1048 }
1049
1050 @SuppressWarnings("unused")
1051 public String on() {
1052 return "invalid";
1053 }
1054
1055 @Override
1056 public boolean equals(Object obj) {
1057 return obj instanceof TestAnnotation;
1058 }
1059
1060 @Override
1061 public int hashCode() {
1062 return 0;
1063 }
1064
1065 @Override
1066 public String toString() {
1067 return "@TestAnnotation";
1068 }
1069 }
1070
1071 @Test
1072 void n02_addRuntimeAnnotations_invalidOnClassReturnType_throwsException() {
1073
1074 var invalidAnnotation = new InvalidOnClassAnnotation();
1075
1076 assertThrows(BeanRuntimeException.class, () -> {
1077 AnnotationProvider.create()
1078 .addRuntimeAnnotations(invalidAnnotation)
1079 .build();
1080 });
1081 }
1082
1083 @Test
1084 void n03_addRuntimeAnnotations_invalidOnReturnType_throwsException() {
1085
1086 var invalidAnnotation = new InvalidOnAnnotation();
1087
1088 assertThrows(BeanRuntimeException.class, () -> {
1089 AnnotationProvider.create()
1090 .addRuntimeAnnotations(invalidAnnotation)
1091 .build();
1092 });
1093 }
1094
1095
1096 private static class ThrowingOnClassAnnotation implements TestAnnotation {
1097 @Override
1098 public String value() {
1099 return "throwing";
1100 }
1101
1102 @Override
1103 public Class<? extends Annotation> annotationType() {
1104 return TestAnnotation.class;
1105 }
1106
1107 @SuppressWarnings("unused")
1108 public Class<?>[] onClass() {
1109 throw new RuntimeException("Test exception from onClass()");
1110 }
1111
1112 @Override
1113 public boolean equals(Object obj) {
1114 return obj instanceof TestAnnotation;
1115 }
1116
1117 @Override
1118 public int hashCode() {
1119 return 0;
1120 }
1121
1122 @Override
1123 public String toString() {
1124 return "@TestAnnotation";
1125 }
1126 }
1127
1128 @Test
1129 void n05_addRuntimeAnnotations_throwingOnClass_coversLine349() {
1130
1131 var throwingAnnotation = new ThrowingOnClassAnnotation();
1132
1133
1134 assertThrows(BeanRuntimeException.class, () -> {
1135 AnnotationProvider.create()
1136 .addRuntimeAnnotations(throwingAnnotation)
1137 .build();
1138 });
1139 }
1140 }
1141