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.TestUtils.*;
22 import static org.apache.juneau.commons.reflect.ElementFlag.*;
23 import static org.junit.jupiter.api.Assertions.*;
24
25 import java.lang.annotation.*;
26 import java.lang.reflect.*;
27 import java.util.*;
28 import java.util.function.*;
29
30 import org.apache.juneau.*;
31 import org.junit.jupiter.api.*;
32
33 class FieldInfo_Test extends TestBase {
34
35 @Documented
36 @Target(FIELD)
37 @Retention(RUNTIME)
38 @Inherited
39 public static @interface A {
40 String value();
41 }
42
43 @Target(FIELD)
44 @Retention(RUNTIME)
45 public static @interface TestAnnotation1 {
46 String value() default "";
47 }
48
49 @Target(FIELD)
50 @Retention(RUNTIME)
51 public static @interface TestAnnotation2 {
52 int value() default 0;
53 }
54
55 @Target(FIELD)
56 @Retention(RUNTIME)
57 public static @interface TestAnnotation3 {
58 String value() default "";
59 }
60
61 private static void check(String expected, Object o) {
62 assertEquals(expected, TO_STRING.apply(o));
63 }
64
65 private static final Function<Object,String> TO_STRING = t -> {
66 if (t == null)
67 return null;
68 if (t instanceof A)
69 return "@A(" + ((A)t).value() + ")";
70 if (t instanceof ClassInfo)
71 return ((ClassInfo)t).getNameSimple();
72 if (t instanceof FieldInfo)
73 return ((FieldInfo)t).getName();
74 if (t instanceof Field)
75 return ((Field)t).getName();
76 return t.toString();
77 };
78
79 private static FieldInfo off(Class<?> c, String name) {
80 try {
81 return FieldInfo.of(c.getDeclaredField(name));
82 } catch (SecurityException | NoSuchFieldException e) {
83 fail(e.getLocalizedMessage());
84 }
85 return null;
86 }
87
88
89
90
91
92 static class A1 {
93 public int f1;
94 }
95 FieldInfo a1_f1 = off(A1.class, "f1");
96
97 public static class B {
98 @A("a1") public int a1;
99 public int a2;
100 }
101 FieldInfo
102 b_a1 = off(B.class, "a1"),
103 b_a2 = off(B.class, "a2");
104
105 abstract static class C {
106 @Deprecated public int deprecated;
107 public int notDeprecated;
108 public int isPublic;
109 protected int isNotPublic;
110 public static int isStatic;
111 public int isNotStatic;
112 public transient int isTransient;
113 public int isNotTransient;
114 }
115 static ClassInfo c = ClassInfo.of(C.class);
116 static FieldInfo
117 c_deprecated = c.getPublicField(x -> x.hasName("deprecated")).get(),
118 c_notDeprecated = c.getPublicField(x -> x.hasName("notDeprecated")).get(),
119 c_isPublic = c.getPublicField(x -> x.hasName("isPublic")).get(),
120 c_isNotPublic = c.getDeclaredField(x -> x.hasName("isNotPublic")).get(),
121 c_isStatic = c.getPublicField(x -> x.hasName("isStatic")).get(),
122 c_isNotStatic = c.getPublicField(x -> x.hasName("isNotStatic")).get(),
123 c_isTransient = c.getPublicField(x -> x.hasName("isTransient")).get(),
124 c_isNotTransient = c.getPublicField(x -> x.hasName("isNotTransient")).get()
125 ;
126
127 abstract static class D {
128 public int isPublic;
129 protected int isProtected;
130 @SuppressWarnings("unused")
131 private int isPrivate;
132 int isDefault;
133 }
134 static ClassInfo d = ClassInfo.of(D.class);
135 static FieldInfo
136 d_isPublic = d.getPublicField(x -> x.hasName("isPublic")).get(),
137 d_isProtected = d.getDeclaredField(x -> x.hasName("isProtected")).get(),
138 d_isPrivate = d.getDeclaredField(x -> x.hasName("isPrivate")).get(),
139 d_isDefault = d.getDeclaredField(x -> x.hasName("isDefault")).get();
140
141 static class E {
142 public int a1;
143 int a2;
144 }
145 static ClassInfo e = ClassInfo.of(E.class);
146 static FieldInfo
147 e_a1 = e.getPublicField(x -> x.hasName("a1")).get(),
148 e_a2 = e.getDeclaredField(x -> x.hasName("a2")).get();
149
150 public static class F {
151 @TestAnnotation1("test1")
152 @TestAnnotation2(42)
153 public String field1;
154
155 @TestAnnotation1("test2")
156 public String field2;
157
158 public String field3;
159 }
160 static ClassInfo f = ClassInfo.of(F.class);
161 static FieldInfo
162 f_field1 = f.getPublicField(x -> x.hasName("field1")).get(),
163 f_field2 = f.getPublicField(x -> x.hasName("field2")).get(),
164 f_field3 = f.getPublicField(x -> x.hasName("field3")).get();
165
166 public static class G {
167 public String field1;
168 public int field2;
169 }
170 static ClassInfo g = ClassInfo.of(G.class);
171 static FieldInfo
172 g_field1 = g.getPublicField(x -> x.hasName("field1")).get(),
173 g_field2 = g.getPublicField(x -> x.hasName("field2")).get();
174
175 public static class InnerClass {
176 public String innerField;
177 }
178 static ClassInfo inner = ClassInfo.of(InnerClass.class);
179 static FieldInfo inner_field = inner.getPublicField(x -> x.hasName("innerField")).get();
180
181 public static class GetSetTest {
182 public String value;
183 public Integer number;
184 }
185 static ClassInfo getSetTest = ClassInfo.of(GetSetTest.class);
186 static FieldInfo
187 getSetTest_value = getSetTest.getPublicField(x -> x.hasName("value")).get(),
188 getSetTest_number = getSetTest.getPublicField(x -> x.hasName("number")).get();
189
190 public enum TestEnum {
191 VALUE1, VALUE2
192 }
193 static ClassInfo testEnum = ClassInfo.of(TestEnum.class);
194 static FieldInfo
195 testEnum_value1 = testEnum.getPublicField(x -> x.hasName("VALUE1")).get(),
196 testEnum_value2 = testEnum.getPublicField(x -> x.hasName("VALUE2")).get();
197
198 public static class EqualsTestClass {
199 public String field1;
200 public int field2;
201 }
202
203
204
205
206 @Test
207 void a001_accessible() {
208 assertDoesNotThrow(()->d_isPublic.accessible());
209 assertDoesNotThrow(()->d_isProtected.accessible());
210 assertDoesNotThrow(()->d_isPrivate.accessible());
211 assertDoesNotThrow(()->d_isDefault.accessible());
212
213
214 var result = d_isPublic.accessible();
215 assertSame(d_isPublic, result);
216 }
217
218
219
220
221 @Test
222 void a002_compareTo() {
223
224
225 var b_a2 = off(B.class, "a2");
226
227
228 assertTrue(b_a2.compareTo(a1_f1) < 0);
229 assertTrue(a1_f1.compareTo(b_a2) > 0);
230 assertEquals(0, a1_f1.compareTo(a1_f1));
231
232
233 assertTrue(b_a1.compareTo(b_a2) < 0);
234 assertTrue(b_a2.compareTo(b_a1) > 0);
235 }
236
237
238
239
240 @Test
241 void a003_get() {
242 var obj = new GetSetTest();
243 obj.value = "test";
244 obj.number = 42;
245
246 assertEquals("test", getSetTest_value.get(obj));
247 assertEquals(Integer.valueOf(42), getSetTest_number.get(obj));
248
249
250 obj.value = null;
251 assertNull(getSetTest_value.get(obj));
252 }
253
254
255
256
257 @Test
258 void a004_getAnnotatableType() {
259 assertEquals(AnnotatableType.FIELD_TYPE, a1_f1.getAnnotatableType());
260 }
261
262
263
264
265 @Test
266 void a005_getAnnotatedType() {
267 var annotatedType = e_a1.getAnnotatedType();
268 assertNotNull(annotatedType);
269 assertEquals(int.class, annotatedType.getType());
270 }
271
272
273
274
275 @Test
276 void a006_getAnnotations() {
277 var annotations1 = f_field1.getAnnotations();
278 assertEquals(2, annotations1.size());
279 assertTrue(annotations1.stream().anyMatch(a -> a.hasSimpleName("TestAnnotation1")));
280 assertTrue(annotations1.stream().anyMatch(a -> a.hasSimpleName("TestAnnotation2")));
281
282 var annotations2 = f_field2.getAnnotations();
283 assertEquals(1, annotations2.size());
284 assertTrue(annotations2.stream().anyMatch(a -> a.hasSimpleName("TestAnnotation1")));
285
286 var annotations3 = f_field3.getAnnotations();
287 assertEquals(0, annotations3.size());
288
289
290 var annotations1_2 = f_field1.getAnnotations();
291 assertSame(annotations1, annotations1_2);
292 }
293
294
295
296
297 @Test
298 void a007_getAnnotations_typed() {
299 var ann1_type1 = f_field1.getAnnotations(TestAnnotation1.class).toList();
300 assertEquals(1, ann1_type1.size());
301 assertEquals("test1", ann1_type1.get(0).getValue().get());
302
303 var ann1_type2 = f_field1.getAnnotations(TestAnnotation2.class).toList();
304 assertEquals(1, ann1_type2.size());
305 assertEquals(42, ann1_type2.get(0).getInt("value").get());
306
307 var ann1_type3 = f_field1.getAnnotations(TestAnnotation3.class).toList();
308 assertEquals(0, ann1_type3.size());
309
310 var ann2_type1 = f_field2.getAnnotations(TestAnnotation1.class).toList();
311 assertEquals(1, ann2_type1.size());
312 assertEquals("test2", ann2_type1.get(0).getValue().get());
313
314 var ann2_type2 = f_field2.getAnnotations(TestAnnotation2.class).toList();
315 assertEquals(0, ann2_type2.size());
316 }
317
318
319
320
321 @Test
322 void a008_getDeclaringClass() {
323 check("A1", a1_f1.getDeclaringClass());
324 check("B", b_a1.getDeclaringClass());
325 }
326
327
328
329
330 @Test
331 void a009_getFieldType() {
332 check("int", e_a1.getFieldType());
333 check("int", e_a2.getFieldType());
334
335
336 var type1 = e_a1.getFieldType();
337 var type2 = e_a1.getFieldType();
338 assertSame(type1, type2);
339 }
340
341
342
343
344 @Test
345 void a010_getFullName() throws Exception {
346 String fullName1 = g_field1.getFullName();
347 String fullName2 = g_field2.getFullName();
348
349
350
351
352 try {
353 Class<?> defaultPkgClassType = Class.forName("DefaultPackageTestClass");
354 ClassInfo defaultPkgClass = ClassInfo.of(defaultPkgClassType);
355 PackageInfo pkg = defaultPkgClass.getPackage();
356 if (pkg == null) {
357
358 FieldInfo defaultPkgField = defaultPkgClass.getPublicField(x -> x.hasName("testField")).get();
359 String fullName = defaultPkgField.getFullName();
360
361 assertTrue(fullName.startsWith("DefaultPackageTestClass"), "Full name should start with class name when package is null: " + fullName);
362 assertTrue(fullName.endsWith(".testField"), "Full name should end with field name: " + fullName);
363
364 assertFalse(fullName.matches("^[a-z][a-z0-9]*(\\.[a-z][a-z0-9]*)+\\."), "Full name should not have package prefix when package is null: " + fullName);
365 }
366 } catch (ClassNotFoundException e) {
367
368 }
369
370 assertTrue(fullName1.endsWith("FieldInfo_Test$G.field1"));
371 assertTrue(fullName2.endsWith("FieldInfo_Test$G.field2"));
372
373 assertTrue(fullName1.startsWith("org.apache.juneau.commons.reflect."));
374 assertTrue(fullName2.startsWith("org.apache.juneau.commons.reflect."));
375
376
377 String name1 = g_field1.getFullName();
378 String name2 = g_field1.getFullName();
379 assertSame(name1, name2);
380
381
382 String innerFullName = inner_field.getFullName();
383 assertTrue(innerFullName.contains("FieldInfo_Test$InnerClass"));
384 assertTrue(innerFullName.endsWith(".innerField"));
385 }
386
387
388
389
390 @Test
391 void a011_getLabel() {
392 var label = a1_f1.getLabel();
393 assertNotNull(label);
394 assertTrue(label.contains("A1"));
395 assertTrue(label.contains("f1"));
396 }
397
398
399
400
401 @Test
402 void a012_getName() {
403 assertEquals("f1", a1_f1.getName());
404 assertEquals("a1", b_a1.getName());
405 assertEquals("a2", b_a2.getName());
406 }
407
408
409
410
411 @Test
412 void a013_hasAnnotation() {
413 assertTrue(b_a1.hasAnnotation(A.class));
414 assertFalse(b_a2.hasAnnotation(A.class));
415 }
416
417
418
419
420 @Test
421 void a014_hasName() {
422 assertTrue(b_a1.hasName("a1"));
423 assertFalse(b_a1.hasName("a2"));
424 assertFalse(b_a1.hasName(null));
425 }
426
427
428
429
430 @Test
431 void a015_inner() {
432 check("f1", a1_f1.inner());
433 var field = a1_f1.inner();
434 assertNotNull(field);
435 assertEquals("f1", field.getName());
436 }
437
438
439
440
441 @Test
442 void a016_is() {
443 assertTrue(c_deprecated.is(DEPRECATED));
444 assertTrue(c_notDeprecated.is(NOT_DEPRECATED));
445 assertTrue(c_isPublic.is(PUBLIC));
446 assertTrue(c_isNotPublic.is(NOT_PUBLIC));
447 assertTrue(c_isStatic.is(STATIC));
448 assertTrue(c_isNotStatic.is(NOT_STATIC));
449 assertTrue(c_isTransient.is(TRANSIENT));
450 assertTrue(c_isNotTransient.is(NOT_TRANSIENT));
451
452 assertFalse(c_deprecated.is(NOT_DEPRECATED));
453 assertFalse(c_notDeprecated.is(DEPRECATED));
454 assertFalse(c_isPublic.is(NOT_PUBLIC));
455 assertFalse(c_isNotPublic.is(PUBLIC));
456 assertFalse(c_isStatic.is(NOT_STATIC));
457 assertFalse(c_isNotStatic.is(STATIC));
458 assertFalse(c_isTransient.is(NOT_TRANSIENT));
459 assertFalse(c_isNotTransient.is(TRANSIENT));
460
461
462 assertTrue(testEnum_value1.is(ENUM_CONSTANT));
463 assertFalse(a1_f1.is(ENUM_CONSTANT));
464 assertTrue(a1_f1.is(NOT_ENUM_CONSTANT));
465 assertFalse(testEnum_value1.is(NOT_ENUM_CONSTANT));
466
467
468 assertFalse(a1_f1.is(SYNTHETIC));
469 assertTrue(a1_f1.is(NOT_SYNTHETIC));
470 assertFalse(b_a1.is(SYNTHETIC));
471 assertTrue(b_a1.is(NOT_SYNTHETIC));
472
473
474 assertThrowsWithMessage(RuntimeException.class, "Invalid flag for element: HAS_PARAMS", () -> c_deprecated.is(HAS_PARAMS));
475 }
476
477
478
479
480 @Test
481 void a017_isAccessible() {
482
483 var privateBefore = d_isPrivate.isAccessible();
484 var protectedBefore = d_isProtected.isAccessible();
485 var defaultBefore = d_isDefault.isAccessible();
486
487
488 d_isPrivate.setAccessible();
489 d_isProtected.setAccessible();
490 d_isDefault.setAccessible();
491
492
493 var privateAfter = d_isPrivate.isAccessible();
494 var protectedAfter = d_isProtected.isAccessible();
495 var defaultAfter = d_isDefault.isAccessible();
496
497
498 assertTrue(privateAfter || !privateBefore, "After setAccessible(), isAccessible() should return true (Java 9+) or false (Java 8)");
499 assertTrue(protectedAfter || !protectedBefore, "After setAccessible(), isAccessible() should return true (Java 9+) or false (Java 8)");
500 assertTrue(defaultAfter || !defaultBefore, "After setAccessible(), isAccessible() should return true (Java 9+) or false (Java 8)");
501
502
503 var publicAccessible = d_isPublic.isAccessible();
504 assertNotNull(publicAccessible);
505 }
506
507
508
509
510 @Test
511 void a018_isAll() {
512 assertTrue(c_deprecated.isAll(DEPRECATED));
513 assertTrue(c_isPublic.isAll(PUBLIC, NOT_PRIVATE));
514 assertFalse(c_deprecated.isAll(DEPRECATED, NOT_DEPRECATED));
515 }
516
517
518
519
520 @Test
521 void a019_isAny() {
522 assertTrue(c_deprecated.isAny(DEPRECATED, NOT_DEPRECATED));
523 assertTrue(c_isPublic.isAny(PUBLIC, PRIVATE));
524 assertFalse(c_deprecated.isAny(NOT_DEPRECATED));
525 }
526
527
528
529
530 @Test
531 void a020_isDeprecated() {
532 assertTrue(c_deprecated.isDeprecated());
533 assertFalse(c_notDeprecated.isDeprecated());
534 }
535
536
537
538
539 @Test
540 void a021_isEnumConstant() {
541 assertTrue(testEnum_value1.isEnumConstant());
542 assertTrue(testEnum_value2.isEnumConstant());
543 assertFalse(a1_f1.isEnumConstant());
544 }
545
546
547
548
549 @Test
550 void a022_isNotDeprecated() {
551 assertFalse(c_deprecated.isNotDeprecated());
552 assertTrue(c_notDeprecated.isNotDeprecated());
553 }
554
555
556
557
558 @Test
559 void a023_isSynthetic() {
560
561 assertFalse(a1_f1.isSynthetic());
562 }
563
564
565
566
567 @Test
568 void a024_isVisible() {
569 assertTrue(d_isPublic.isVisible(Visibility.PUBLIC));
570 assertTrue(d_isPublic.isVisible(Visibility.PROTECTED));
571 assertTrue(d_isPublic.isVisible(Visibility.PRIVATE));
572 assertTrue(d_isPublic.isVisible(Visibility.DEFAULT));
573
574 assertFalse(d_isProtected.isVisible(Visibility.PUBLIC));
575 assertTrue(d_isProtected.isVisible(Visibility.PROTECTED));
576 assertTrue(d_isProtected.isVisible(Visibility.PRIVATE));
577 assertTrue(d_isProtected.isVisible(Visibility.DEFAULT));
578
579 assertFalse(d_isPrivate.isVisible(Visibility.PUBLIC));
580 assertFalse(d_isPrivate.isVisible(Visibility.PROTECTED));
581 assertTrue(d_isPrivate.isVisible(Visibility.PRIVATE));
582 assertFalse(d_isPrivate.isVisible(Visibility.DEFAULT));
583
584 assertFalse(d_isDefault.isVisible(Visibility.PUBLIC));
585 assertFalse(d_isDefault.isVisible(Visibility.PROTECTED));
586 assertTrue(d_isDefault.isVisible(Visibility.PRIVATE));
587 assertTrue(d_isDefault.isVisible(Visibility.DEFAULT));
588 }
589
590
591
592
593 @Test
594 void a025_of_withClass() {
595 check("f1", FieldInfo.of(ClassInfo.of(A1.class), a1_f1.inner()));
596 }
597
598
599
600
601 @Test
602 void a026_of_withoutClass() {
603 check("f1", FieldInfo.of(a1_f1.inner()));
604
605
606 assertThrows(IllegalArgumentException.class, () -> FieldInfo.of((Field)null));
607 assertThrows(IllegalArgumentException.class, () -> FieldInfo.of((ClassInfo)null, null));
608 }
609
610
611
612
613 @Test
614 void a027_set() {
615 var obj = new GetSetTest();
616
617 getSetTest_value.set(obj, "newValue");
618 assertEquals("newValue", obj.value);
619
620 getSetTest_number.set(obj, 100);
621 assertEquals(100, obj.number);
622
623
624 getSetTest_value.set(obj, null);
625 assertNull(obj.value);
626 }
627
628
629
630
631 @Test
632 void a028_setAccessible() {
633 assertDoesNotThrow(()->d_isPublic.setAccessible());
634 assertDoesNotThrow(()->d_isProtected.setAccessible());
635 assertDoesNotThrow(()->d_isPrivate.setAccessible());
636 assertDoesNotThrow(()->d_isDefault.setAccessible());
637 }
638
639
640
641
642 @Test
643 void a029_setIfNull() {
644 var obj = new GetSetTest();
645
646
647 obj.value = null;
648 getSetTest_value.setIfNull(obj, "defaultValue");
649 assertEquals("defaultValue", obj.value);
650
651
652 obj.value = "existing";
653 getSetTest_value.setIfNull(obj, "shouldNotSet");
654 assertEquals("existing", obj.value);
655 }
656
657
658
659
660 @Test
661 void a030_toGenericString() {
662 var str = e_a1.toGenericString();
663 assertNotNull(str);
664 assertTrue(str.contains("int"));
665 assertTrue(str.contains("a1"));
666 }
667
668
669
670
671 @Test
672 void a031_toString() {
673 assertEquals("org.apache.juneau.commons.reflect.FieldInfo_Test$E.a1", e_a1.toString());
674 }
675
676
677
678
679 @Test
680 void a032_equals_hashCode() throws Exception {
681
682 Field f1 = EqualsTestClass.class.getField("field1");
683 FieldInfo fi1a = FieldInfo.of(f1);
684 FieldInfo fi1b = FieldInfo.of(f1);
685
686 Field f2 = EqualsTestClass.class.getField("field2");
687 FieldInfo fi2 = FieldInfo.of(f2);
688
689
690 assertEquals(fi1a, fi1b);
691 assertEquals(fi1a.hashCode(), fi1b.hashCode());
692
693
694 assertNotEquals(fi1a, fi2);
695 assertNotEquals(fi1a, null);
696 assertNotEquals(fi1a, "not a FieldInfo");
697
698
699 assertEquals(fi1a, fi1a);
700
701
702 assertEquals(fi1a, fi1b);
703 assertEquals(fi1b, fi1a);
704
705
706 FieldInfo fi1c = FieldInfo.of(f1);
707 assertEquals(fi1a, fi1b);
708 assertEquals(fi1b, fi1c);
709 assertEquals(fi1a, fi1c);
710
711
712 Map<FieldInfo, String> map = new HashMap<>();
713 map.put(fi1a, "value1");
714 assertEquals("value1", map.get(fi1b));
715 assertEquals("value1", map.get(fi1c));
716
717
718 map.put(fi2, "value2");
719 assertEquals("value2", map.get(fi2));
720 assertNotEquals("value2", map.get(fi1a));
721
722
723 Set<FieldInfo> set = new HashSet<>();
724 set.add(fi1a);
725 assertTrue(set.contains(fi1b));
726 assertTrue(set.contains(fi1c));
727 assertFalse(set.contains(fi2));
728 }
729 }
730