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.junit.jupiter.api.Assertions.*;
22
23 import java.lang.annotation.*;
24 import org.apache.juneau.*;
25 import org.apache.juneau.commons.annotation.*;
26 import org.junit.jupiter.api.*;
27
28 class AnnotationInfo_Test extends TestBase {
29
30
31
32
33
34 @Target(TYPE)
35 @Retention(RUNTIME)
36 public static @interface TestAnnotation {
37 String value() default "default";
38 }
39
40 @Target(TYPE)
41 @Retention(RUNTIME)
42 public static @interface MultiTypeAnnotation {
43 String stringValue() default "default";
44
45 int intValue() default 0;
46
47 boolean boolValue() default true;
48
49 long longValue() default 100L;
50
51 double doubleValue() default 3.14;
52
53 float floatValue() default 2.5f;
54
55 Class<?> classValue() default String.class;
56
57 String[] stringArray() default { "a", "b" };
58
59 Class<?>[] classArray() default { String.class, Integer.class };
60 }
61
62 @Target(TYPE)
63 @Retention(RUNTIME)
64 public static @interface RankedAnnotation {
65 int rank() default 0;
66 }
67
68 @Target(TYPE)
69 @Retention(RUNTIME)
70 public static @interface UnrankedAnnotation {
71 String value() default "";
72 }
73
74 @Target(TYPE)
75 @Retention(RUNTIME)
76 public static @interface RankWithWrongReturnTypeAnnotation {
77 String rank() default "";
78 }
79
80 @Target(TYPE)
81 @Retention(RUNTIME)
82 public static @interface ClassArrayAnnotation {
83 Class<?>[] classes() default {};
84 }
85
86 @Target(TYPE)
87 @Retention(RUNTIME)
88 public static @interface ClassValueAnnotation {
89 Class<?> value() default String.class;
90 }
91
92 @Target(TYPE)
93 @Retention(RUNTIME)
94 @Documented
95 public static @interface DocumentedAnnotation {}
96
97 @Target(TYPE)
98 @Retention(RUNTIME)
99 @AnnotationGroup(GroupAnnotation.class)
100 public static @interface GroupAnnotation {}
101
102 @Target(TYPE)
103 @Retention(RUNTIME)
104 @AnnotationGroup(GroupAnnotation.class)
105 public static @interface GroupMember1 {}
106
107 @Target(TYPE)
108 @Retention(RUNTIME)
109 @AnnotationGroup(GroupAnnotation.class)
110 public static @interface GroupMember2 {}
111
112 @Target(TYPE)
113 @Retention(RUNTIME)
114 public static @interface NotInGroup {}
115
116 @TestAnnotation("test")
117 public static class TestClass {}
118
119 @MultiTypeAnnotation(stringValue = "test", intValue = 123, boolValue = false, longValue = 999L, doubleValue = 1.23, floatValue = 4.56f, classValue = Integer.class, stringArray = { "x", "y",
120 "z" }, classArray = { Long.class, Double.class })
121 public static class MultiTypeClass {}
122
123 @RankedAnnotation(rank = 5)
124 public static class RankedClass {}
125
126 @UnrankedAnnotation
127 public static class UnrankedClass {}
128
129 @RankWithWrongReturnTypeAnnotation
130 public static class RankWithWrongReturnTypeClass {}
131
132 @ClassArrayAnnotation(classes = { String.class, Integer.class })
133 public static class ClassArrayClass {}
134
135 @ClassValueAnnotation(Integer.class)
136 public static class ClassValueClass {}
137
138 @DocumentedAnnotation
139 public static class DocumentedClass {}
140
141 @GroupMember1
142 @GroupMember2
143 @NotInGroup
144 public static class GroupTestClass {}
145
146 @Target(TYPE)
147 @Retention(RUNTIME)
148 public static @interface ToMapTestAnnotation {
149 String value() default "default";
150 String[] arrayValue() default {};
151 String[] nonEmptyArray() default {"a", "b"};
152 String[] emptyArrayWithNonEmptyDefault() default {"default"};
153 }
154
155 @ToMapTestAnnotation(value = "custom", arrayValue = {}, nonEmptyArray = {"x"}, emptyArrayWithNonEmptyDefault = {})
156 public static class ToMapTestClass {}
157
158
159
160
161 @Test
162 void a001_annotationType() {
163 var ci = ClassInfo.of(TestClass.class);
164 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
165 assertNotNull(ai);
166 assertEquals(TestAnnotation.class, ai.annotationType());
167 }
168
169
170
171
172 @Test
173 void a002_cast() {
174 var ci = ClassInfo.of(TestClass.class);
175 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
176 assertNotNull(ai);
177
178
179 var casted = ai.cast(TestAnnotation.class);
180 assertNotNull(casted);
181 assertSame(ai, casted);
182
183
184 var casted2 = ai.cast(Deprecated.class);
185 assertNull(casted2);
186 }
187
188
189
190
191 @Test
192 void a003_equals() {
193 var ci = ClassInfo.of(TestClass.class);
194 var ai1 = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
195 var ai2 = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
196
197 assertNotNull(ai1);
198 assertNotNull(ai2);
199
200 assertEquals(ai1, ai2);
201 assertEquals(ai1.hashCode(), ai2.hashCode());
202
203
204 @Deprecated
205 class DeprecatedClass {}
206 var ci2 = ClassInfo.of(DeprecatedClass.class);
207 var ai3 = ci2.getAnnotations(Deprecated.class).findFirst().orElse(null);
208 assertNotNull(ai3);
209 assertNotEquals(ai1, ai3);
210
211
212 var ai4 = AnnotationInfo.of(ci, ci.inner().getAnnotation(TestAnnotation.class));
213 assertEquals(ai1, ai4);
214
215
216 var annotation = ci.inner().getAnnotation(TestAnnotation.class);
217 assertEquals(ai1, annotation);
218 }
219
220
221
222
223 @Test
224 void a004_getBoolean() {
225 var ci = ClassInfo.of(MultiTypeClass.class);
226 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
227 assertNotNull(ai);
228
229 assertTrue(ai.getBoolean("boolValue").isPresent());
230 assertEquals(false, ai.getBoolean("boolValue").get());
231 assertFalse(ai.getBoolean("nonexistent").isPresent());
232 }
233
234
235
236
237 @Test
238 void a005_getClassArray() {
239 var ci = ClassInfo.of(MultiTypeClass.class);
240 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
241 assertNotNull(ai);
242
243 assertTrue(ai.getClassArray("classArray").isPresent());
244 var array = ai.getClassArray("classArray").get();
245 assertNotNull(array);
246 assertEquals(2, array.length);
247 assertEquals(Long.class, array[0]);
248 assertEquals(Double.class, array[1]);
249 assertFalse(ai.getClassArray("nonexistent").isPresent());
250 }
251
252
253
254
255 @Test
256 void a006_getClassArray_typed() {
257 var ci = ClassInfo.of(ClassArrayClass.class);
258 var ai = ci.getAnnotations(ClassArrayAnnotation.class).findFirst().orElse(null);
259 assertNotNull(ai);
260
261
262 var classes = ai.getClassArray("classes", Object.class);
263 assertTrue(classes.isPresent());
264 var array = classes.get();
265 assertEquals(2, array.length);
266 assertEquals(String.class, array[0]);
267 assertEquals(Integer.class, array[1]);
268
269
270 var classes2 = ai.getClassArray("classes", Exception.class);
271 assertFalse(classes2.isPresent());
272 }
273
274
275
276
277 @Test
278 void a007_getClassValue() {
279 var ci = ClassInfo.of(MultiTypeClass.class);
280 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
281 assertNotNull(ai);
282
283 assertTrue(ai.getClassValue("classValue").isPresent());
284 assertEquals(Integer.class, ai.getClassValue("classValue").get());
285 assertFalse(ai.getClassValue("nonexistent").isPresent());
286 }
287
288
289
290
291 @Test
292 void a008_getClassValue_typed() {
293 var ci = ClassInfo.of(ClassValueClass.class);
294 var ai = ci.getAnnotations(ClassValueAnnotation.class).findFirst().orElse(null);
295 assertNotNull(ai);
296
297
298 var numberClass = ai.getClassValue("value", Number.class);
299 assertTrue(numberClass.isPresent());
300 assertEquals(Integer.class, numberClass.get());
301
302
303 var exceptionClass = ai.getClassValue("value", Exception.class);
304 assertFalse(exceptionClass.isPresent());
305 }
306
307
308
309
310 @Test
311 void a009_getDouble() {
312 var ci = ClassInfo.of(MultiTypeClass.class);
313 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
314 assertNotNull(ai);
315
316 assertTrue(ai.getDouble("doubleValue").isPresent());
317 assertEquals(1.23, ai.getDouble("doubleValue").get(), 0.001);
318 assertFalse(ai.getDouble("nonexistent").isPresent());
319 }
320
321
322
323
324 @Test
325 void a010_getFloat() {
326 var ci = ClassInfo.of(MultiTypeClass.class);
327 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
328 assertNotNull(ai);
329
330 assertTrue(ai.getFloat("floatValue").isPresent());
331 assertEquals(4.56f, ai.getFloat("floatValue").get(), 0.001);
332 assertFalse(ai.getFloat("nonexistent").isPresent());
333 }
334
335
336
337
338 @Test
339 void a011_getInt() {
340 var ci = ClassInfo.of(MultiTypeClass.class);
341 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
342 assertNotNull(ai);
343
344 assertTrue(ai.getInt("intValue").isPresent());
345 assertEquals(123, ai.getInt("intValue").get());
346 assertFalse(ai.getInt("nonexistent").isPresent());
347 }
348
349
350
351
352 @Test
353 void a012_getLong() {
354 var ci = ClassInfo.of(MultiTypeClass.class);
355 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
356 assertNotNull(ai);
357
358 assertTrue(ai.getLong("longValue").isPresent());
359 assertEquals(999L, ai.getLong("longValue").get());
360 assertFalse(ai.getLong("nonexistent").isPresent());
361 }
362
363
364
365
366 @Test
367 void a013_getMethod() {
368 var ci = ClassInfo.of(TestClass.class);
369 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
370 assertNotNull(ai);
371
372
373 var method = ai.getMethod("value");
374 assertTrue(method.isPresent());
375 assertEquals("value", method.get().getSimpleName());
376
377
378 var method2 = ai.getMethod("nonexistent");
379 assertFalse(method2.isPresent());
380 }
381
382
383
384
385 @Test
386 void a014_getName() {
387 var ci = ClassInfo.of(TestClass.class);
388 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
389 assertNotNull(ai);
390 assertEquals("TestAnnotation", ai.getName());
391 }
392
393
394
395
396 @Test
397 void a015_getRank() {
398
399 var ci1 = ClassInfo.of(RankedClass.class);
400 var ai1 = ci1.getAnnotations(RankedAnnotation.class).findFirst().orElse(null);
401 assertNotNull(ai1);
402 assertEquals(5, ai1.getRank());
403
404
405 var ci2 = ClassInfo.of(UnrankedClass.class);
406 var ai2 = ci2.getAnnotations(UnrankedAnnotation.class).findFirst().orElse(null);
407 assertNotNull(ai2);
408 assertEquals(0, ai2.getRank());
409
410
411 var ci3 = ClassInfo.of(RankWithWrongReturnTypeClass.class);
412 var ai3 = ci3.getAnnotations(RankWithWrongReturnTypeAnnotation.class).findFirst().orElse(null);
413 assertNotNull(ai3);
414 assertEquals(0, ai3.getRank());
415 }
416
417
418
419
420 @Test
421 void a016_getReturnType() {
422 var ci = ClassInfo.of(MultiTypeClass.class);
423 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
424 assertNotNull(ai);
425
426 assertTrue(ai.getReturnType("stringValue").isPresent());
427 assertEquals(String.class, ai.getReturnType("stringValue").get().inner());
428 assertEquals(int.class, ai.getReturnType("intValue").get().inner());
429 assertEquals(boolean.class, ai.getReturnType("boolValue").get().inner());
430 assertEquals(long.class, ai.getReturnType("longValue").get().inner());
431 assertEquals(double.class, ai.getReturnType("doubleValue").get().inner());
432 assertEquals(float.class, ai.getReturnType("floatValue").get().inner());
433 assertEquals(Class.class, ai.getReturnType("classValue").get().inner());
434 assertEquals(String[].class, ai.getReturnType("stringArray").get().inner());
435 assertEquals(Class[].class, ai.getReturnType("classArray").get().inner());
436
437
438 assertFalse(ai.getReturnType("nonexistent").isPresent());
439 }
440
441
442
443
444 @Test
445 void a017_getString() {
446 var ci = ClassInfo.of(MultiTypeClass.class);
447 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
448 assertNotNull(ai);
449
450 assertTrue(ai.getString("stringValue").isPresent());
451 assertEquals("test", ai.getString("stringValue").get());
452 assertFalse(ai.getString("nonexistent").isPresent());
453 }
454
455
456
457
458 @Test
459 void a018_getStringArray() {
460 var ci = ClassInfo.of(MultiTypeClass.class);
461 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
462 assertNotNull(ai);
463
464 assertTrue(ai.getStringArray("stringArray").isPresent());
465 var array = ai.getStringArray("stringArray").get();
466 assertNotNull(array);
467 assertEquals(3, array.length);
468 assertEquals("x", array[0]);
469 assertEquals("y", array[1]);
470 assertEquals("z", array[2]);
471 assertFalse(ai.getStringArray("nonexistent").isPresent());
472 }
473
474
475
476
477 @Test
478 void a019_getValue() {
479 var ci = ClassInfo.of(TestClass.class);
480 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
481 assertNotNull(ai);
482
483 var value = ai.getValue();
484 assertTrue(value.isPresent());
485 assertEquals("test", value.get());
486 }
487
488
489
490
491 @Test
492 void a020_getValue_typed() {
493 var ci = ClassInfo.of(MultiTypeClass.class);
494 var ai = ci.getAnnotations(MultiTypeAnnotation.class).findFirst().orElse(null);
495 assertNotNull(ai);
496
497
498 var stringValue = ai.getValue(String.class, "stringValue");
499 assertTrue(stringValue.isPresent());
500 assertEquals("test", stringValue.get());
501
502
503 var intValue = ai.getValue(int.class, "intValue");
504 assertTrue(intValue.isPresent());
505 assertEquals(123, intValue.get());
506
507
508 var intValue2 = ai.getValue(Integer.class, "stringValue");
509 assertFalse(intValue2.isPresent());
510 }
511
512
513
514
515 @Test
516 void a021_hasAnnotation() {
517 var ci = ClassInfo.of(DocumentedClass.class);
518 var ai = ci.getAnnotations(DocumentedAnnotation.class).findFirst().orElse(null);
519 assertNotNull(ai);
520
521
522 assertTrue(ai.hasAnnotation(Documented.class));
523
524
525 var ci2 = ClassInfo.of(TestClass.class);
526 var ai2 = ci2.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
527 assertNotNull(ai2);
528 assertFalse(ai2.hasAnnotation(Documented.class));
529 }
530
531
532
533
534 @Test
535 void a022_hasName() {
536 var ci = ClassInfo.of(TestClass.class);
537 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
538 assertNotNull(ai);
539
540 var fullyQualifiedName = TestAnnotation.class.getName();
541 assertTrue(ai.hasName(fullyQualifiedName));
542 assertFalse(ai.hasName("TestAnnotation"));
543 }
544
545
546
547
548 @Test
549 void a023_hasSimpleName() {
550 var ci = ClassInfo.of(TestClass.class);
551 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
552 assertNotNull(ai);
553
554 assertTrue(ai.hasSimpleName("TestAnnotation"));
555 assertFalse(ai.hasSimpleName(TestAnnotation.class.getName()));
556 }
557
558
559
560
561 @Test
562 void a024_hashCode() {
563 var ci = ClassInfo.of(TestClass.class);
564 var ai1 = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
565 var ai2 = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
566
567 assertNotNull(ai1);
568 assertNotNull(ai2);
569 assertEquals(ai1.hashCode(), ai2.hashCode());
570 }
571
572
573
574
575 @Test
576 void a025_inner() {
577 var ci = ClassInfo.of(TestClass.class);
578 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
579 assertNotNull(ai);
580
581 var annotation = ai.inner();
582 assertNotNull(annotation);
583 assertEquals(TestAnnotation.class, annotation.annotationType());
584 assertEquals("test", annotation.value());
585 }
586
587
588
589
590 @Test
591 void a026_isInGroup() {
592 var ci = ClassInfo.of(GroupTestClass.class);
593 var groupMember1 = ci.getAnnotations(GroupMember1.class).findFirst().orElse(null);
594 var groupMember2 = ci.getAnnotations(GroupMember2.class).findFirst().orElse(null);
595 var notInGroup = ci.getAnnotations(NotInGroup.class).findFirst().orElse(null);
596
597 assertNotNull(groupMember1);
598 assertNotNull(groupMember2);
599 assertNotNull(notInGroup);
600
601 assertTrue(groupMember1.isInGroup(GroupAnnotation.class));
602 assertTrue(groupMember2.isInGroup(GroupAnnotation.class));
603 assertFalse(notInGroup.isInGroup(GroupAnnotation.class));
604 }
605
606
607
608
609 @Test
610 void a027_isType() {
611 var ci = ClassInfo.of(TestClass.class);
612 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
613 assertNotNull(ai);
614
615 assertTrue(ai.isType(TestAnnotation.class));
616 assertFalse(ai.isType(Deprecated.class));
617 }
618
619
620
621
622 @Test
623 void a028_of() {
624 var ci = ClassInfo.of(TestClass.class);
625 var annotation = ci.inner().getAnnotation(TestAnnotation.class);
626 var ai = AnnotationInfo.of(ci, annotation);
627
628 assertNotNull(ai);
629 assertEquals(TestAnnotation.class, ai.annotationType());
630 assertEquals("test", ai.getValue().orElse(null));
631
632
633 assertThrows(IllegalArgumentException.class, () -> AnnotationInfo.of(ci, null));
634 }
635
636
637
638
639 @Test
640 void a029_properties() {
641 var ci = ClassInfo.of(TestClass.class);
642 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
643 assertNotNull(ai);
644
645 var map = ai.properties();
646 assertNotNull(map);
647 assertTrue(map.containsKey("CLASS_TYPE"));
648 assertTrue(map.containsKey("@TestAnnotation"));
649
650 var annotationMap = (java.util.Map<String,Object>)map.get("@TestAnnotation");
651 assertNotNull(annotationMap);
652 assertEquals("test", annotationMap.get("value"));
653
654
655 var ci2 = ClassInfo.of(ToMapTestClass.class);
656 var ai2 = ci2.getAnnotations(ToMapTestAnnotation.class).findFirst().orElse(null);
657 assertNotNull(ai2);
658
659 var map2 = ai2.properties();
660 assertNotNull(map2);
661 var annotationMap2 = (java.util.Map<String,Object>)map2.get("@ToMapTestAnnotation");
662 assertNotNull(annotationMap2);
663
664
665 assertEquals("custom", annotationMap2.get("value"));
666
667
668 assertTrue(annotationMap2.containsKey("nonEmptyArray"));
669
670
671 assertTrue(annotationMap2.containsKey("emptyArrayWithNonEmptyDefault"));
672
673
674 assertFalse(annotationMap2.containsKey("arrayValue"));
675
676
677 var annotationType = ToMapTestAnnotation.class;
678 var handler = new java.lang.reflect.InvocationHandler() {
679 @Override
680 public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable {
681 if (method.getName().equals("value")) {
682 throw new RuntimeException("Test exception");
683 }
684 if (method.getName().equals("annotationType")) {
685 return annotationType;
686 }
687 if (method.getName().equals("toString")) {
688 return "@ToMapTestAnnotation";
689 }
690 if (method.getName().equals("hashCode")) {
691 return 0;
692 }
693 if (method.getName().equals("equals")) {
694 return false;
695 }
696 return method.getDefaultValue();
697 }
698 };
699
700 var proxyAnnotation = (ToMapTestAnnotation)java.lang.reflect.Proxy.newProxyInstance(
701 annotationType.getClassLoader(),
702 new Class[]{annotationType},
703 handler
704 );
705
706 var ci3 = ClassInfo.of(ToMapTestClass.class);
707 var ai3 = AnnotationInfo.of(ci3, proxyAnnotation);
708
709 var map3 = ai3.properties();
710 assertNotNull(map3);
711 var annotationMap3 = (java.util.Map<String,Object>)map3.get("@ToMapTestAnnotation");
712 assertNotNull(annotationMap3);
713
714
715 assertTrue(annotationMap3.containsKey("value"));
716 var value = annotationMap3.get("value");
717 assertNotNull(value);
718
719 assertTrue(value instanceof String);
720 }
721
722
723
724
725 @Test
726 void a030_toSimpleString() {
727 var ci = ClassInfo.of(TestClass.class);
728 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
729 assertNotNull(ai);
730
731 var str = ai.toSimpleString();
732 assertNotNull(str);
733 assertTrue(str.contains("@TestAnnotation"));
734 assertTrue(str.contains("on="));
735 }
736
737
738
739
740 @Test
741 void a031_toString() {
742 var ci = ClassInfo.of(TestClass.class);
743 var ai = ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
744 assertNotNull(ai);
745
746 var str = ai.toString();
747 assertNotNull(str);
748
749 assertTrue(str.contains("CLASS_TYPE") || str.contains("@TestAnnotation"));
750 }
751 }
752