1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.commons.annotation;
18
19 import static org.apache.juneau.junit.bct.BctAssertions.*;
20 import static org.junit.jupiter.api.Assertions.*;
21
22 import java.lang.annotation.*;
23 import java.lang.reflect.*;
24
25 import org.apache.juneau.*;
26 import org.apache.juneau.commons.reflect.*;
27 import org.junit.jupiter.api.*;
28
29 class AppliedAnnotationObject_Test extends TestBase {
30
31 private static final String CNAME = AppliedAnnotationObject_Test.class.getName();
32
33
34
35
36
37 @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR })
38 @Retention(RetentionPolicy.RUNTIME)
39 public @interface TA {
40 String[] on() default {};
41
42 String value() default "";
43
44 int number() default 0;
45 }
46
47
48
49
50 public static class TAO extends AppliedAnnotationObject implements TA {
51
52 private final String value;
53 private final int number;
54
55 public static class Builder extends AppliedAnnotationObject.Builder {
56 String value = "";
57 int number = 0;
58
59 public Builder() {
60 super(TA.class);
61 }
62
63 public Builder value(String value) {
64 this.value = value;
65 return this;
66 }
67
68 public Builder number(int number) {
69 this.number = number;
70 return this;
71 }
72
73 @Override
74 public Builder on(String...value) {
75 super.on(value);
76 return this;
77 }
78
79 public TA build() {
80 return new TAO(this);
81 }
82 }
83
84 public static Builder create() {
85 return new Builder();
86 }
87
88 public TAO(Builder b) {
89 super(b);
90 value = b.value;
91 number = b.number;
92 }
93
94 @Override
95 public String value() {
96 return value;
97 }
98
99 @Override
100 public int number() {
101 return number;
102 }
103 }
104
105
106
107
108
109 public static class TC {
110 public String field1;
111 public int field2;
112
113 public TC() {}
114
115 public TC(String s) {}
116
117 public void method1() {}
118
119 public String method2(int x) {
120 return null;
121 }
122 }
123
124 public static class TC2 {}
125
126
127
128
129
130 @Nested
131 @DisplayName("Basic on() tests with strings")
132 class A_BasicOnTests extends TestBase {
133
134 @Test
135 void a01_noTargets() {
136 var a = TAO.create().build();
137 assertList(a.on());
138 }
139
140 @Test
141 void a02_singleTarget() {
142 var a = TAO.create().on("com.example.MyClass").build();
143
144 assertList(a.on(), "com.example.MyClass");
145 }
146
147 @Test
148 void a03_multipleTargets() {
149 var a = TAO.create().on("com.example.Class1").on("com.example.Class2").build();
150
151 assertList(a.on(), "com.example.Class1", "com.example.Class2");
152 }
153
154 @Test
155 void a04_varargsTargets() {
156 var a = TAO.create().on("target1", "target2", "target3").build();
157
158 assertList(a.on(), "target1", "target2", "target3");
159 }
160
161 @Test
162 void a05_withOtherProperties() {
163 var a = TAO.create().on("com.example.MyClass").value("test").number(42).build();
164
165 assertBean(a, "on,value,number", "[com.example.MyClass],test,42");
166 }
167 }
168
169 @Nested
170 @DisplayName("Equality and hashcode tests")
171 class B_EqualityAndHashCodeTests extends TestBase {
172
173 @Test
174 void b01_sameTargets() {
175 var a1 = TAO.create().on("target1", "target2").value("test").build();
176
177 var a2 = TAO.create().on("target1", "target2").value("test").build();
178
179 assertEquals(a1, a2);
180 assertEquals(a1.hashCode(), a2.hashCode());
181 }
182
183 @Test
184 void b02_differentTargets() {
185 var a1 = TAO.create().on("target1").build();
186
187 var a2 = TAO.create().on("target2").build();
188
189 assertNotEquals(a1, a2);
190 }
191
192 @Test
193 void b03_differentTargetOrder() {
194
195 var a1 = TAO.create().on("target1", "target2").build();
196
197 var a2 = TAO.create().on("target2", "target1").build();
198
199 assertNotEquals(a1, a2);
200 }
201
202 @Test
203 void b04_noTargetsVsWithTargets() {
204 var a1 = TAO.create().build();
205 var a2 = TAO.create().on("target1").build();
206
207 assertNotEquals(a1, a2);
208 }
209 }
210
211 @Nested
212 @DisplayName("BuilderT - Class targeting tests")
213 class C_BuilderTTests extends TestBase {
214
215
216
217
218 public static class C extends AppliedOnClassAnnotationObject implements TA {
219
220 private final String value;
221
222 public static class Builder extends AppliedAnnotationObject.BuilderT {
223 String value = "";
224
225 public Builder() {
226 super(TA.class);
227 }
228
229 public Builder value(String value) {
230 this.value = value;
231 return this;
232 }
233
234 @Override
235 public Builder on(String...value) {
236 super.on(value);
237 return this;
238 }
239
240 @Override
241 public Builder on(Class<?>...value) {
242 super.on(value);
243 return this;
244 }
245
246 @Override
247 public Builder on(ClassInfo...value) {
248 super.on(value);
249 return this;
250 }
251
252 @Override
253 public Builder onClass(Class<?>...value) {
254 super.onClass(value);
255 return this;
256 }
257
258 @Override
259 public Builder onClass(ClassInfo...value) {
260 super.onClass(value);
261 return this;
262 }
263
264 public TA build() {
265 return new C(this);
266 }
267 }
268
269 public static Builder create() {
270 return new Builder();
271 }
272
273 public C(Builder b) {
274 super(b);
275 value = b.value;
276 }
277
278 @Override
279 public String value() {
280 return value;
281 }
282
283 @Override
284 public int number() {
285 return 0;
286 }
287 }
288
289 @Test
290 void c01_onClassArray() {
291 var a = C.create().on(TC.class, TC2.class).build();
292
293 assertList(a.on(), CNAME + "$TC", CNAME + "$TC2");
294 }
295
296 @Test
297 void c02_onClassInfo() {
298 var ci1 = ClassInfo.of(TC.class);
299 var ci2 = ClassInfo.of(TC2.class);
300
301 var a = C.create().on(ci1, ci2).build();
302
303 assertList(a.on(), CNAME + "$TC", CNAME + "$TC2");
304 }
305
306 @Test
307 void c03_mixedTargeting() {
308 var a = C.create().on("com.example.StringTarget").on(TC.class).build();
309
310 assertList(a.on(), "com.example.StringTarget", CNAME + "$TC");
311 }
312
313 @Test
314 void c04_onClassClass() {
315 var a = (AppliedOnClassAnnotationObject)C.create().onClass(TC.class, TC2.class).build();
316
317 assertList(a.onClass(), TC.class, TC2.class);
318 }
319
320 @Test
321 void c05_onClassClassInfo() {
322 var ci1 = ClassInfo.of(TC.class);
323 var ci2 = ClassInfo.of(TC2.class);
324
325 var a = (AppliedOnClassAnnotationObject)C.create().onClass(ci1, ci2).build();
326
327 assertList(a.onClass(), TC.class, TC2.class);
328 }
329 }
330
331 @Nested
332 @DisplayName("BuilderM - Method targeting tests")
333 class D_BuilderMTests extends TestBase {
334
335
336
337
338 public static class D extends AppliedAnnotationObject implements TA {
339
340 public static class Builder extends AppliedAnnotationObject.BuilderM {
341
342 public Builder() {
343 super(TA.class);
344 }
345
346 @Override
347 public Builder on(String...value) {
348 super.on(value);
349 return this;
350 }
351
352 @Override
353 public Builder on(Method...value) {
354 super.on(value);
355 return this;
356 }
357
358 @Override
359 public Builder on(MethodInfo...value) {
360 super.on(value);
361 return this;
362 }
363
364 public TA build() {
365 return new D(this);
366 }
367 }
368
369 public static Builder create() {
370 return new Builder();
371 }
372
373 public D(Builder b) {
374 super(b);
375 }
376
377 @Override
378 public String value() {
379 return "";
380 }
381
382 @Override
383 public int number() {
384 return 0;
385 }
386 }
387
388 @Test
389 void d01_onMethod() throws Exception {
390 var m1 = TC.class.getMethod("method1");
391 var m2 = TC.class.getMethod("method2", int.class);
392
393 var a = D.create().on(m1, m2).build();
394
395 assertList(a.on(), CNAME + "$TC.method1()", CNAME + "$TC.method2(int)");
396 }
397
398 @Test
399 void d02_onMethodInfo() throws Exception {
400 var mi1 = MethodInfo.of(TC.class.getMethod("method1"));
401 var mi2 = MethodInfo.of(TC.class.getMethod("method2", int.class));
402
403 var a = D.create().on(mi1, mi2).build();
404
405 assertList(a.on(), CNAME + "$TC.method1()", CNAME + "$TC.method2(int)");
406 }
407 }
408
409 @Nested
410 @DisplayName("BuilderC - Constructor targeting tests")
411 class E_BuilderCTests extends TestBase {
412
413
414
415
416 public static class E extends AppliedAnnotationObject implements TA {
417
418 public static class Builder extends AppliedAnnotationObject.BuilderC {
419
420 public Builder() {
421 super(TA.class);
422 }
423
424 @Override
425 public Builder on(String...value) {
426 super.on(value);
427 return this;
428 }
429
430 @Override
431 public Builder on(Constructor<?>...value) {
432 super.on(value);
433 return this;
434 }
435
436 @Override
437 public Builder on(ConstructorInfo...value) {
438 super.on(value);
439 return this;
440 }
441
442 public TA build() {
443 return new E(this);
444 }
445 }
446
447 public static Builder create() {
448 return new Builder();
449 }
450
451 public E(Builder b) {
452 super(b);
453 }
454
455 @Override
456 public String value() {
457 return "";
458 }
459
460 @Override
461 public int number() {
462 return 0;
463 }
464 }
465
466 @Test
467 void e01_onConstructor() throws Exception {
468 var c1 = TC.class.getConstructor();
469 var c2 = TC.class.getConstructor(String.class);
470
471 var a = E.create().on(c1, c2).build();
472
473 assertList(a.on(), CNAME + "$TC()", CNAME + "$TC(java.lang.String)");
474 }
475
476 @Test
477 void e02_onConstructorInfo() throws Exception {
478 var ci1 = ConstructorInfo.of(TC.class.getConstructor());
479 var ci2 = ConstructorInfo.of(TC.class.getConstructor(String.class));
480
481 var a = E.create().on(ci1, ci2).build();
482
483 assertList(a.on(), CNAME + "$TC()", CNAME + "$TC(java.lang.String)");
484 }
485 }
486
487 @Nested
488 @DisplayName("BuilderMF - Method and Field targeting tests")
489 class F_BuilderMFTests extends TestBase {
490
491
492
493
494 public static class F extends AppliedAnnotationObject implements TA {
495
496 public static class Builder extends AppliedAnnotationObject.BuilderMF {
497
498 public Builder() {
499 super(TA.class);
500 }
501
502 @Override
503 public Builder on(String...value) {
504 super.on(value);
505 return this;
506 }
507
508 @Override
509 public Builder on(Method...value) {
510 super.on(value);
511 return this;
512 }
513
514 @Override
515 public Builder on(MethodInfo...value) {
516 super.on(value);
517 return this;
518 }
519
520 @Override
521 public Builder on(Field...value) {
522 super.on(value);
523 return this;
524 }
525
526 @Override
527 public Builder on(FieldInfo...value) {
528 super.on(value);
529 return this;
530 }
531
532 public TA build() {
533 return new F(this);
534 }
535 }
536
537 public static Builder create() {
538 return new Builder();
539 }
540
541 public F(Builder b) {
542 super(b);
543 }
544
545 @Override
546 public String value() {
547 return "";
548 }
549
550 @Override
551 public int number() {
552 return 0;
553 }
554 }
555
556 @Test
557 void f01_onField() throws Exception {
558 var f1 = TC.class.getField("field1");
559 var f2 = TC.class.getField("field2");
560
561 var a = F.create().on(f1, f2).build();
562
563 assertList(a.on(), CNAME + "$TC.field1", CNAME + "$TC.field2");
564 }
565
566 @Test
567 void f02_onFieldInfo() throws Exception {
568 var fi1 = FieldInfo.of(ClassInfo.of(TC.class), TC.class.getField("field1"));
569 var fi2 = FieldInfo.of(ClassInfo.of(TC.class), TC.class.getField("field2"));
570
571 var a = F.create().on(fi1, fi2).build();
572
573 assertList(a.on(), CNAME + "$TC.field1", CNAME + "$TC.field2");
574 }
575
576 @Test
577 void f03_mixedMethodsAndFields() throws Exception {
578 var m = TC.class.getMethod("method1");
579 var f = TC.class.getField("field1");
580
581 var a = F.create().on(m).on(f).build();
582
583 assertList(a.on(), CNAME + "$TC.method1()", CNAME + "$TC.field1");
584 }
585
586 @Test
587 void f04_onMethodInfo() throws Exception {
588 var mi1 = MethodInfo.of(TC.class.getMethod("method1"));
589 var mi2 = MethodInfo.of(TC.class.getMethod("method2", int.class));
590
591 var a = F.create().on(mi1, mi2).build();
592
593 assertList(a.on(), CNAME + "$TC.method1()", CNAME + "$TC.method2(int)");
594 }
595 }
596
597 @Nested
598 @DisplayName("BuilderTM - Class and Method targeting tests")
599 class G_BuilderTMTests extends TestBase {
600
601
602
603
604 public static class G extends AppliedOnClassAnnotationObject implements TA {
605
606 public static class Builder extends AppliedAnnotationObject.BuilderTM {
607
608 public Builder() {
609 super(TA.class);
610 }
611
612 @Override
613 public Builder on(String...value) {
614 super.on(value);
615 return this;
616 }
617
618 @Override
619 public Builder on(Class<?>...value) {
620 super.on(value);
621 return this;
622 }
623
624 @Override
625 public Builder on(ClassInfo...value) {
626 super.on(value);
627 return this;
628 }
629
630 @Override
631 public Builder on(Method...value) {
632 super.on(value);
633 return this;
634 }
635
636 @Override
637 public Builder on(MethodInfo...value) {
638 super.on(value);
639 return this;
640 }
641
642 @Override
643 public Builder onClass(Class<?>...value) {
644 super.onClass(value);
645 return this;
646 }
647
648 public TA build() {
649 return new G(this);
650 }
651 }
652
653 public static Builder create() {
654 return new Builder();
655 }
656
657 public G(Builder b) {
658 super(b);
659 }
660
661 @Override
662 public String value() {
663 return "";
664 }
665
666 @Override
667 public int number() {
668 return 0;
669 }
670 }
671
672 @Test
673 void g01_onClassAndMethod() throws Exception {
674 var m = TC.class.getMethod("method1");
675
676 var a = G.create().on(TC.class).on(m).build();
677
678 assertList(a.on(), CNAME + "$TC", CNAME + "$TC.method1()");
679 }
680
681 @Test
682 void g02_onMethodInfo() throws Exception {
683 var mi = MethodInfo.of(TC.class.getMethod("method1"));
684
685 var a = G.create().on(mi).build();
686
687 assertList(a.on(), CNAME + "$TC.method1()");
688 }
689
690 @Test
691 void g03_onClassClass() {
692 var a = (AppliedOnClassAnnotationObject) G.create().onClass(TC.class, TC2.class).build();
693
694 assertList(a.onClass(), TC.class, TC2.class);
695 }
696 }
697
698 @Nested
699 @DisplayName("BuilderTMF - Class, Method, and Field targeting tests")
700 class H_BuilderTMFTests extends TestBase {
701
702
703
704
705 public static class H extends AppliedOnClassAnnotationObject implements TA {
706
707 public static class Builder extends AppliedAnnotationObject.BuilderTMF {
708
709 public Builder() {
710 super(TA.class);
711 }
712
713 @Override
714 public Builder on(String...value) {
715 super.on(value);
716 return this;
717 }
718
719 @Override
720 public Builder on(Class<?>...value) {
721 super.on(value);
722 return this;
723 }
724
725 @Override
726 public Builder on(ClassInfo...value) {
727 super.on(value);
728 return this;
729 }
730
731 @Override
732 public Builder on(Method...value) {
733 super.on(value);
734 return this;
735 }
736
737 @Override
738 public Builder on(MethodInfo...value) {
739 super.on(value);
740 return this;
741 }
742
743 @Override
744 public Builder on(Field...value) {
745 super.on(value);
746 return this;
747 }
748
749 @Override
750 public Builder on(FieldInfo...value) {
751 super.on(value);
752 return this;
753 }
754
755 public TA build() {
756 return new H(this);
757 }
758 }
759
760 public static Builder create() {
761 return new Builder();
762 }
763
764 public H(Builder b) {
765 super(b);
766 }
767
768 @Override
769 public String value() {
770 return "";
771 }
772
773 @Override
774 public int number() {
775 return 0;
776 }
777 }
778
779 @Test
780 void h01_onClassMethodAndField() throws Exception {
781 var m = TC.class.getMethod("method1");
782 var f = TC.class.getField("field1");
783
784 var a = H.create().on(TC.class).on(m).on(f).build();
785
786 assertList(a.on(), CNAME + "$TC", CNAME + "$TC.method1()", CNAME + "$TC.field1");
787 }
788
789 @Test
790 void h02_onMethodInfo() throws Exception {
791 var mi = MethodInfo.of(TC.class.getMethod("method1"));
792
793 var a = H.create().on(mi).build();
794
795 assertList(a.on(), CNAME + "$TC.method1()");
796 }
797
798 @Test
799 void h03_onFieldInfo() throws Exception {
800 var fi = FieldInfo.of(ClassInfo.of(TC.class), TC.class.getField("field1"));
801
802 var a = H.create().on(fi).build();
803
804 assertList(a.on(), CNAME + "$TC.field1");
805 }
806 }
807
808 @Nested
809 @DisplayName("BuilderTMFC - Class, Method, Field, and Constructor targeting tests")
810 class I_BuilderTMFCTests extends TestBase {
811
812
813
814
815 public static class I extends AppliedOnClassAnnotationObject implements TA {
816
817 public static class Builder extends AppliedAnnotationObject.BuilderTMFC {
818
819 public Builder() {
820 super(TA.class);
821 }
822
823 @Override
824 public Builder on(String...value) {
825 super.on(value);
826 return this;
827 }
828
829 @Override
830 public Builder on(Class<?>...value) {
831 super.on(value);
832 return this;
833 }
834
835 @Override
836 public Builder on(Method...value) {
837 super.on(value);
838 return this;
839 }
840
841 @Override
842 public Builder on(MethodInfo...value) {
843 super.on(value);
844 return this;
845 }
846
847 @Override
848 public Builder on(Field...value) {
849 super.on(value);
850 return this;
851 }
852
853 @Override
854 public Builder on(FieldInfo...value) {
855 super.on(value);
856 return this;
857 }
858
859 @Override
860 public Builder on(Constructor<?>...value) {
861 super.on(value);
862 return this;
863 }
864
865 @Override
866 public Builder on(ConstructorInfo...value) {
867 super.on(value);
868 return this;
869 }
870
871 public TA build() {
872 return new I(this);
873 }
874 }
875
876 public static Builder create() {
877 return new Builder();
878 }
879
880 public I(Builder b) {
881 super(b);
882 }
883
884 @Override
885 public String value() {
886 return "";
887 }
888
889 @Override
890 public int number() {
891 return 0;
892 }
893 }
894
895 @Test
896 void i01_onAllTypes() throws Exception {
897 var m = TC.class.getMethod("method1");
898 var f = TC.class.getField("field1");
899 var c = TC.class.getConstructor();
900
901 var a = I.create().on(TC.class).on(m).on(f).on(c).build();
902
903 assertList(a.on(), CNAME + "$TC", CNAME + "$TC.method1()", CNAME + "$TC.field1", CNAME + "$TC()");
904 }
905
906 @Test
907 void i02_onMethodInfo() throws Exception {
908 var mi = MethodInfo.of(TC.class.getMethod("method1"));
909
910 var a = I.create().on(mi).build();
911
912 assertList(a.on(), CNAME + "$TC.method1()");
913 }
914
915 @Test
916 void i03_onFieldInfo() throws Exception {
917 var fi = FieldInfo.of(ClassInfo.of(TC.class), TC.class.getField("field1"));
918
919 var a = I.create().on(fi).build();
920
921 assertList(a.on(), CNAME + "$TC.field1");
922 }
923
924 @Test
925 void i04_onConstructorInfo() throws Exception {
926 var ci = ConstructorInfo.of(TC.class.getConstructor(String.class));
927
928 var a = I.create().on(ci).build();
929
930 assertList(a.on(), CNAME + "$TC(java.lang.String)");
931 }
932 }
933
934 @Nested
935 @DisplayName("Fluent API tests")
936 class J_FluentApiTests extends TestBase {
937
938 @Test
939 void j01_chaining() {
940 var a = TAO.create().on("target1").value("test").on("target2").number(42).on("target3").build();
941
942 assertBean(a, "on,value,number", "[target1,target2,target3],test,42");
943 }
944 }
945
946 @Nested
947 @DisplayName("toMap() tests")
948 class K_ToMapTests extends TestBase {
949
950 @Test
951 void k01_withTargets() {
952 var a = TAO.create().on("target1", "target2").value("test").build();
953
954 var map = ((TAO)a).propertyMap();
955 assertBean(map, "on,value", "[target1,target2],test");
956 }
957 }
958
959 @Nested
960 @DisplayName("Edge case tests")
961 class L_EdgeCaseTests extends TestBase {
962
963 @Test
964 void l01_emptyTargets() {
965 var a = TAO.create().on().build();
966
967 assertList(a.on());
968 }
969
970 @Test
971 void l02_builderReuse() {
972 var builder = TAO.create().on("target1").value("test");
973
974 var a1 = builder.build();
975 var a2 = builder.build();
976
977
978 assertNotSame(a1, a2);
979 assertEquals(a1, a2);
980 }
981 }
982
983 @Nested
984 @DisplayName("Null validation tests")
985 class M_NullValidationTests extends TestBase {
986
987 @Test
988 void m01_nullClass_throwsException() {
989 assertThrows(IllegalArgumentException.class, () -> C_BuilderTTests.C.create().on((Class<?>)null).build());
990 }
991
992 @Test
993 void m02_nullClassInfo_throwsException() {
994 assertThrows(IllegalArgumentException.class, () -> C_BuilderTTests.C.create().on((ClassInfo)null).build());
995 }
996
997 @Test
998 void m03_nullMethod_throwsException() {
999 assertThrows(IllegalArgumentException.class, () -> D_BuilderMTests.D.create().on((java.lang.reflect.Method)null).build());
1000 }
1001
1002 @Test
1003 void m04_nullMethodInfo_throwsException() {
1004 assertThrows(IllegalArgumentException.class, () -> D_BuilderMTests.D.create().on((MethodInfo)null).build());
1005 }
1006
1007 @Test
1008 void m05_nullField_throwsException() {
1009 assertThrows(IllegalArgumentException.class, () -> F_BuilderMFTests.F.create().on((java.lang.reflect.Field)null).build());
1010 }
1011
1012 @Test
1013 void m06_nullFieldInfo_throwsException() {
1014 assertThrows(IllegalArgumentException.class, () -> F_BuilderMFTests.F.create().on((FieldInfo)null).build());
1015 }
1016
1017 @Test
1018 void m07_nullConstructor_throwsException() {
1019 assertThrows(IllegalArgumentException.class, () -> E_BuilderCTests.E.create().on((java.lang.reflect.Constructor<?>)null).build());
1020 }
1021
1022 @Test
1023 void m08_nullConstructorInfo_throwsException() {
1024 assertThrows(IllegalArgumentException.class, () -> E_BuilderCTests.E.create().on((ConstructorInfo)null).build());
1025 }
1026 }
1027 }