This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 550c2c8dd9 org.apache.juneau.common.reflect API improvements
550c2c8dd9 is described below

commit 550c2c8dd9bd889007c550e398e2f6fff2d7df8c
Author: James Bognar <[email protected]>
AuthorDate: Tue Nov 25 07:09:42 2025 -0500

    org.apache.juneau.common.reflect API improvements
---
 .../common/annotation/AnnotationObject_Test.java   | 215 ++----
 .../annotation/AppliedAnnotationObject_Test.java   | 810 ++++++++++++++-------
 .../AppliedOnClassAnnotationObject_Test.java       | 417 +++++++++++
 3 files changed, 1011 insertions(+), 431 deletions(-)

diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AnnotationObject_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AnnotationObject_Test.java
index 26d5c1d353..75b237b66a 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AnnotationObject_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AnnotationObject_Test.java
@@ -16,6 +16,7 @@
  */
 package org.apache.juneau.common.annotation;
 
+import static org.apache.juneau.junit.bct.BctAssertions.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import java.lang.annotation.*;
@@ -30,19 +31,22 @@ class AnnotationObject_Test extends TestBase {
        // Test annotation for testing purposes
        
//------------------------------------------------------------------------------------------------------------------
 
-       @Target({ElementType.TYPE, ElementType.METHOD})
+       @Target({ ElementType.TYPE, ElementType.METHOD })
        @Retention(RetentionPolicy.RUNTIME)
-       public @interface TestAnnotation {
+       public @interface TA {
                String value() default "";
+
                int number() default 0;
+
                boolean flag() default false;
+
                String[] array() default {};
        }
 
        /**
-        * Implementation of TestAnnotation using AnnotationObject
+        * Implementation of TA using AnnotationObject
         */
-       public static class TestAnnotationObject extends AnnotationObject 
implements TestAnnotation {
+       public static class T extends AnnotationObject implements TA {
 
                private final String value;
                private final int number;
@@ -56,31 +60,31 @@ class AnnotationObject_Test extends TestBase {
                        String[] array = {};
 
                        public Builder() {
-                               super(TestAnnotation.class);
+                               super(TA.class);
                        }
 
-                       public Builder value(String value) {
-                               this.value = value;
+                       public Builder value(String _value) {
+                               value = _value;
                                return this;
                        }
 
-                       public Builder number(int number) {
-                               this.number = number;
+                       public Builder number(int value) {
+                               number = value;
                                return this;
                        }
 
-                       public Builder flag(boolean flag) {
-                               this.flag = flag;
+                       public Builder flag(boolean value) {
+                               flag = value;
                                return this;
                        }
 
-                       public Builder array(String...array) {
-                               this.array = array;
+                       public Builder array(String...value) {
+                               array = value;
                                return this;
                        }
 
-                       public TestAnnotation build() {
-                               return new TestAnnotationObject(this);
+                       public TA build() {
+                               return new T(this);
                        }
                }
 
@@ -88,12 +92,12 @@ class AnnotationObject_Test extends TestBase {
                        return new Builder();
                }
 
-               public TestAnnotationObject(Builder b) {
+               public T(Builder b) {
                        super(b);
                        value = b.value;
                        number = b.number;
                        flag = b.flag;
-                       this.array = Arrays.copyOf(b.array, b.array.length);
+                       array = Arrays.copyOf(b.array, b.array.length);
                }
 
                @Override
@@ -123,32 +127,20 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void a01_basic_defaultValues() {
-               var a = TestAnnotationObject.create().build();
-               assertEquals("", a.value());
-               assertEquals(0, a.number());
-               assertEquals(false, a.flag());
-               assertArrayEquals(new String[0], a.array());
+               var a = T.create().build();
+               assertBean(a, "value,number,flag,array", ",0,false,[]");
        }
 
        @Test
        void a02_basic_customValues() {
-               var a = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42)
-                       .flag(true)
-                       .array("a", "b", "c")
-                       .build();
-
-               assertEquals("test", a.value());
-               assertEquals(42, a.number());
-               assertEquals(true, a.flag());
-               assertArrayEquals(new String[]{"a", "b", "c"}, a.array());
+               var a = T.create().value("a").number(1).flag(true).array("b1", 
"b2").build();
+               assertBean(a, "value,number,flag,array", "a,1,true,[b1,b2]");
        }
 
        @Test
        void a03_basic_annotationType() {
-               var a = TestAnnotationObject.create().build();
-               assertEquals(TestAnnotation.class, a.annotationType());
+               var a = T.create().build();
+               assertEquals(TA.class, a.annotationType());
        }
 
        
//------------------------------------------------------------------------------------------------------------------
@@ -157,19 +149,9 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void b01_equality_identical() {
-               var a1 = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42)
-                       .flag(true)
-                       .array("a", "b")
-                       .build();
-
-               var a2 = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42)
-                       .flag(true)
-                       .array("a", "b")
-                       .build();
+               var a1 = T.create().value("a").number(1).flag(true).array("b1", 
"b2").build();
+
+               var a2 = T.create().value("a").number(1).flag(true).array("b1", 
"b2").build();
 
                assertEquals(a1, a2);
                assertEquals(a1.hashCode(), a2.hashCode());
@@ -177,29 +159,20 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void b02_equality_different() {
-               var a1 = TestAnnotationObject.create()
-                       .value("test1")
-                       .build();
+               var a1 = T.create().value("a1").build();
 
-               var a2 = TestAnnotationObject.create()
-                       .value("test2")
-                       .build();
+               var a2 = T.create().value("a2").build();
 
                assertNotEquals(a1, a2);
        }
 
        @Test
        void b03_equality_withDeclaredAnnotation() {
-               @TestAnnotation(value="test", number=42, flag=true, array={"a", 
"b"})
-               class TestClass {}
+               @TA(value = "a", number = 1, flag = true, array = { "b1", "b2" 
})
+               class B {}
 
-               var declared = 
TestClass.class.getAnnotation(TestAnnotation.class);
-               var programmatic = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42)
-                       .flag(true)
-                       .array("a", "b")
-                       .build();
+               var declared = B.class.getAnnotation(TA.class);
+               var programmatic = 
T.create().value("a").number(1).flag(true).array("b1", "b2").build();
 
                assertEquals(declared, programmatic);
                assertEquals(declared.hashCode(), programmatic.hashCode());
@@ -207,10 +180,7 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void b04_hashCode_consistency() {
-               var a = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42)
-                       .build();
+               var a = T.create().value("a").number(1).build();
 
                var hash1 = a.hashCode();
                var hash2 = a.hashCode();
@@ -219,8 +189,8 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void b05_hashCode_notNegativeOne() {
-               var a = TestAnnotationObject.create().build();
-               assertNotEquals(-1, a.hashCode(), "hashCode should not be -1 
after postConstruct");
+               var a = T.create().build();
+               assertNotEquals(-1, a.hashCode());
        }
 
        
//------------------------------------------------------------------------------------------------------------------
@@ -229,43 +199,24 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void c01_toMap_defaultValues() {
-               var a = TestAnnotationObject.create().build();
-               var map = ((TestAnnotationObject)a).toMap();
-
-               assertNotNull(map);
-               assertEquals("", map.get("value"));
-               assertEquals(0, map.get("number"));
-               assertEquals(false, map.get("flag"));
-               assertArrayEquals(new String[0], (String[])map.get("array"));
+               var a = T.create().build();
+               assertBean(((T)a).toMap(), "value,number,flag,array", 
",0,false,[]");
        }
 
        @Test
        void c02_toMap_customValues() {
-               var a = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42)
-                       .flag(true)
-                       .array("a", "b")
-                       .build();
-               var map = ((TestAnnotationObject)a).toMap();
-
-               assertEquals("test", map.get("value"));
-               assertEquals(42, map.get("number"));
-               assertEquals(true, map.get("flag"));
-               assertArrayEquals(new String[]{"a", "b"}, 
(String[])map.get("array"));
+               var a = T.create().value("a").number(1).flag(true).array("b1", 
"b2").build();
+
+               assertBean(((T)a).toMap(), "value,number,flag,array", 
"a,1,true,[b1,b2]");
        }
 
        @Test
        void c03_toMap_keySorted() {
-               var a = TestAnnotationObject.create().build();
-               var map = ((TestAnnotationObject)a).toMap();
+               var a = T.create().build();
+               var map = ((T)a).toMap();
 
                // Map should be ordered by key name
-               var keys = new ArrayList<>(map.keySet());
-               assertEquals("array", keys.get(0));
-               assertEquals("flag", keys.get(1));
-               assertEquals("number", keys.get(2));
-               assertEquals("value", keys.get(3));
+               assertList(map.keySet(), "array", "flag", "number", "value");
        }
 
        
//------------------------------------------------------------------------------------------------------------------
@@ -274,7 +225,7 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void d01_toString_notNull() {
-               var a = TestAnnotationObject.create().build();
+               var a = T.create().build();
                var str = a.toString();
                assertNotNull(str);
                assertFalse(str.isEmpty());
@@ -282,14 +233,9 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void d02_toString_containsValues() {
-               var a = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42)
-                       .build();
-               var str = a.toString();
+               var a = T.create().value("a").number(1).build();
 
-               assertTrue(str.contains("test"));
-               assertTrue(str.contains("42"));
+               assertContainsAll(a.toString(), "a", "1");
        }
 
        
//------------------------------------------------------------------------------------------------------------------
@@ -298,11 +244,7 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void e01_constructor_nullAnnotationType() {
-               var e = assertThrows(IllegalArgumentException.class, () -> {
-                       new AnnotationObject.Builder(null);
-               });
-
-               assertTrue(e.getMessage().contains("annotationType"));
+               assertThrows(IllegalArgumentException.class, () -> new 
AnnotationObject.Builder(null));
        }
 
        
//------------------------------------------------------------------------------------------------------------------
@@ -311,22 +253,14 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void f01_builder_fluentApi() {
-               var a = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42)
-                       .flag(true)
-                       .array("a", "b")
-                       .build();
-
-               assertNotNull(a);
-               assertEquals("test", a.value());
+               var a = T.create().value("a").number(1).flag(true).array("b1", 
"b2").build();
+
+               assertBean(a, "value,number,flag,array", "a,1,true,[b1,b2]");
        }
 
        @Test
        void f02_builder_multipleBuilds() {
-               var builder = TestAnnotationObject.create()
-                       .value("test")
-                       .number(42);
+               var builder = T.create().value("a").number(1);
 
                var a1 = builder.build();
                var a2 = builder.build();
@@ -338,8 +272,8 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void f03_builder_getAnnotationType() {
-               var builder = TestAnnotationObject.create();
-               assertEquals(TestAnnotation.class, builder.getAnnotationType());
+               var builder = T.create();
+               assertEquals(TA.class, builder.getAnnotationType());
        }
 
        
//------------------------------------------------------------------------------------------------------------------
@@ -349,13 +283,9 @@ class AnnotationObject_Test extends TestBase {
        @Test
        void g01_arrayEquality_emptyVsNull() {
                // Empty array and null should be handled consistently
-               var a1 = TestAnnotationObject.create()
-                       .array()
-                       .build();
+               var a1 = T.create().array().build();
 
-               var a2 = TestAnnotationObject.create()
-                       .array(new String[0])
-                       .build();
+               var a2 = T.create().array(new String[0]).build();
 
                assertEquals(a1, a2);
        }
@@ -363,13 +293,9 @@ class AnnotationObject_Test extends TestBase {
        @Test
        void g02_arrayEquality_deepEquals() {
                // Arrays with same content should be equal
-               var a1 = TestAnnotationObject.create()
-                       .array("a", "b", "c")
-                       .build();
+               var a1 = T.create().array("a", "b", "c").build();
 
-               var a2 = TestAnnotationObject.create()
-                       .array(new String[]{"a", "b", "c"})
-                       .build();
+               var a2 = T.create().array(new String[] { "a", "b", "c" 
}).build();
 
                assertEquals(a1, a2);
        }
@@ -377,20 +303,16 @@ class AnnotationObject_Test extends TestBase {
        @Test
        void g03_arrayEquality_differentOrder() {
                // Arrays with different order should not be equal
-               var a1 = TestAnnotationObject.create()
-                       .array("a", "b", "c")
-                       .build();
+               var a1 = T.create().array("a", "b", "c").build();
 
-               var a2 = TestAnnotationObject.create()
-                       .array("c", "b", "a")
-                       .build();
+               var a2 = T.create().array("c", "b", "a").build();
 
                assertNotEquals(a1, a2);
        }
 
        @Test
        void g04_equality_differentType() {
-               var a = TestAnnotationObject.create().build();
+               var a = T.create().build();
                var other = new Object();
 
                assertNotEquals(a, other);
@@ -398,7 +320,7 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void g05_equality_null() {
-               var a = TestAnnotationObject.create().build();
+               var a = T.create().build();
                assertNotEquals(a, null);
        }
 
@@ -408,9 +330,6 @@ class AnnotationObject_Test extends TestBase {
 
        @Test
        void h01_nullBuilder_throwsException() {
-               assertThrows(IllegalArgumentException.class, () ->
-                       new TestAnnotationObject(null)
-               );
+               assertThrows(IllegalArgumentException.class, () -> new T(null));
        }
-}
-
+}
\ No newline at end of file
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AppliedAnnotationObject_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AppliedAnnotationObject_Test.java
index 7fbd0090ca..a6c46f5af0 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AppliedAnnotationObject_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AppliedAnnotationObject_Test.java
@@ -16,6 +16,7 @@
  */
 package org.apache.juneau.common.annotation;
 
+import static org.apache.juneau.junit.bct.BctAssertions.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import java.lang.annotation.*;
@@ -33,18 +34,20 @@ class AppliedAnnotationObject_Test extends TestBase {
        // Test annotation for testing purposes
        
//------------------------------------------------------------------------------------------------------------------
 
-       @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, 
ElementType.CONSTRUCTOR})
+       @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, 
ElementType.CONSTRUCTOR })
        @Retention(RetentionPolicy.RUNTIME)
-       public @interface TestAppliedAnnotation {
+       public @interface TA {
                String[] on() default {};
+
                String value() default "";
+
                int number() default 0;
        }
 
        /**
-        * Implementation of TestAppliedAnnotation using 
AppliedAnnotationObject with basic Builder
+        * Implementation of TA using AppliedAnnotationObject with basic Builder
         */
-       public static class TestAppliedAnnotationObject extends 
AppliedAnnotationObject implements TestAppliedAnnotation {
+       public static class TAO extends AppliedAnnotationObject implements TA {
 
                private final String value;
                private final int number;
@@ -54,7 +57,7 @@ class AppliedAnnotationObject_Test extends TestBase {
                        int number = 0;
 
                        public Builder() {
-                               super(TestAppliedAnnotation.class);
+                               super(TA.class);
                        }
 
                        public Builder value(String value) {
@@ -73,8 +76,8 @@ class AppliedAnnotationObject_Test extends TestBase {
                                return this;
                        }
 
-                       public TestAppliedAnnotation build() {
-                               return new TestAppliedAnnotationObject(this);
+                       public TA build() {
+                               return new TAO(this);
                        }
                }
 
@@ -82,7 +85,7 @@ class AppliedAnnotationObject_Test extends TestBase {
                        return new Builder();
                }
 
-               public TestAppliedAnnotationObject(Builder b) {
+               public TAO(Builder b) {
                        super(b);
                        value = b.value;
                        number = b.number;
@@ -103,18 +106,22 @@ class AppliedAnnotationObject_Test extends TestBase {
        // Test classes for targeting
        
//------------------------------------------------------------------------------------------------------------------
 
-       public static class TargetClass1 {
+       public static class TC {
                public String field1;
                public int field2;
 
-               public TargetClass1() {}
-               public TargetClass1(String s) {}
+               public TC() {}
+
+               public TC(String s) {}
 
                public void method1() {}
-               public String method2(int x) { return null; }
+
+               public String method2(int x) {
+                       return null;
+               }
        }
 
-       public static class TargetClass2 {}
+       public static class TC2 {}
 
        
//------------------------------------------------------------------------------------------------------------------
        // Nested test classes
@@ -122,109 +129,80 @@ class AppliedAnnotationObject_Test extends TestBase {
 
        @Nested
        @DisplayName("Basic on() tests with strings")
-       class BasicOnTests {
+       class A_BasicOnTests extends TestBase {
 
                @Test
-               void noTargets() {
-                       var a = TestAppliedAnnotationObject.create().build();
-                       assertArrayEquals(new String[0], a.on());
+               void a01_noTargets() {
+                       var a = TAO.create().build();
+                       assertList(a.on());
                }
 
                @Test
-               void singleTarget() {
-                       var a = TestAppliedAnnotationObject.create()
-                               .on("com.example.MyClass")
-                               .build();
+               void a02_singleTarget() {
+                       var a = TAO.create().on("com.example.MyClass").build();
 
-                       assertArrayEquals(new String[]{"com.example.MyClass"}, 
a.on());
+                       assertList(a.on(), "com.example.MyClass");
                }
 
                @Test
-               void multipleTargets() {
-                       var a = TestAppliedAnnotationObject.create()
-                               .on("com.example.Class1")
-                               .on("com.example.Class2")
-                               .build();
+               void a03_multipleTargets() {
+                       var a = 
TAO.create().on("com.example.Class1").on("com.example.Class2").build();
 
-                       assertArrayEquals(new String[]{"com.example.Class1", 
"com.example.Class2"}, a.on());
+                       assertList(a.on(), "com.example.Class1", 
"com.example.Class2");
                }
 
                @Test
-               void varargsTargets() {
-                       var a = TestAppliedAnnotationObject.create()
-                               .on("target1", "target2", "target3")
-                               .build();
+               void a04_varargsTargets() {
+                       var a = TAO.create().on("target1", "target2", 
"target3").build();
 
-                       assertArrayEquals(new String[]{"target1", "target2", 
"target3"}, a.on());
+                       assertList(a.on(), "target1", "target2", "target3");
                }
 
                @Test
-               void withOtherProperties() {
-                       var a = TestAppliedAnnotationObject.create()
-                               .on("com.example.MyClass")
-                               .value("test")
-                               .number(42)
-                               .build();
+               void a05_withOtherProperties() {
+                       var a = 
TAO.create().on("com.example.MyClass").value("test").number(42).build();
 
-                       assertArrayEquals(new String[]{"com.example.MyClass"}, 
a.on());
-                       assertEquals("test", a.value());
-                       assertEquals(42, a.number());
+                       assertBean(a, "on,value,number", 
"[com.example.MyClass],test,42");
                }
        }
 
        @Nested
        @DisplayName("Equality and hashcode tests")
-       class EqualityAndHashCodeTests {
+       class B_EqualityAndHashCodeTests extends TestBase {
 
                @Test
-               void sameTargets() {
-                       var a1 = TestAppliedAnnotationObject.create()
-                               .on("target1", "target2")
-                               .value("test")
-                               .build();
+               void b01_sameTargets() {
+                       var a1 = TAO.create().on("target1", 
"target2").value("test").build();
 
-                       var a2 = TestAppliedAnnotationObject.create()
-                               .on("target1", "target2")
-                               .value("test")
-                               .build();
+                       var a2 = TAO.create().on("target1", 
"target2").value("test").build();
 
                        assertEquals(a1, a2);
                        assertEquals(a1.hashCode(), a2.hashCode());
                }
 
                @Test
-               void differentTargets() {
-                       var a1 = TestAppliedAnnotationObject.create()
-                               .on("target1")
-                               .build();
+               void b02_differentTargets() {
+                       var a1 = TAO.create().on("target1").build();
 
-                       var a2 = TestAppliedAnnotationObject.create()
-                               .on("target2")
-                               .build();
+                       var a2 = TAO.create().on("target2").build();
 
                        assertNotEquals(a1, a2);
                }
 
                @Test
-               void differentTargetOrder() {
+               void b03_differentTargetOrder() {
                        // Arrays with different order should not be equal
-                       var a1 = TestAppliedAnnotationObject.create()
-                               .on("target1", "target2")
-                               .build();
+                       var a1 = TAO.create().on("target1", "target2").build();
 
-                       var a2 = TestAppliedAnnotationObject.create()
-                               .on("target2", "target1")
-                               .build();
+                       var a2 = TAO.create().on("target2", "target1").build();
 
                        assertNotEquals(a1, a2);
                }
 
                @Test
-               void noTargetsVsWithTargets() {
-                       var a1 = TestAppliedAnnotationObject.create().build();
-                       var a2 = TestAppliedAnnotationObject.create()
-                               .on("target1")
-                               .build();
+               void b04_noTargetsVsWithTargets() {
+                       var a1 = TAO.create().build();
+                       var a2 = TAO.create().on("target1").build();
 
                        assertNotEquals(a1, a2);
                }
@@ -232,12 +210,12 @@ class AppliedAnnotationObject_Test extends TestBase {
 
        @Nested
        @DisplayName("BuilderT - Class targeting tests")
-       class BuilderTTests {
+       class C_BuilderTTests extends TestBase {
 
                /**
                 * Implementation with BuilderT for class targeting
                 */
-               public static class TestAppliedAnnotationObjectT extends 
AppliedAnnotationObject implements TestAppliedAnnotation {
+               public static class C extends AppliedOnClassAnnotationObject 
implements TA {
 
                        private final String value;
 
@@ -245,7 +223,7 @@ class AppliedAnnotationObject_Test extends TestBase {
                                String value = "";
 
                                public Builder() {
-                                       super(TestAppliedAnnotation.class);
+                                       super(TA.class);
                                }
 
                                public Builder value(String value) {
@@ -271,8 +249,20 @@ class AppliedAnnotationObject_Test extends TestBase {
                                        return this;
                                }
 
-                               public TestAppliedAnnotation build() {
-                                       return new 
TestAppliedAnnotationObjectT(this);
+                               @Override
+                               public Builder onClass(Class<?>...value) {
+                                       super.onClass(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder onClass(ClassInfo...value) {
+                                       super.onClass(value);
+                                       return this;
+                               }
+
+                               public TA build() {
+                                       return new C(this);
                                }
                        }
 
@@ -280,7 +270,7 @@ class AppliedAnnotationObject_Test extends TestBase {
                                return new Builder();
                        }
 
-                       public TestAppliedAnnotationObjectT(Builder b) {
+                       public C(Builder b) {
                                super(b);
                                value = b.value;
                        }
@@ -297,62 +287,60 @@ class AppliedAnnotationObject_Test extends TestBase {
                }
 
                @Test
-               void onClassArray() {
-                       var a = TestAppliedAnnotationObjectT.create()
-                               .on(TargetClass1.class, TargetClass2.class)
-                               .build();
+               void c01_onClassArray() {
+                       var a = C.create().on(TC.class, TC2.class).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1",
-                               CNAME + "$TargetClass2"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC", CNAME + "$TC2");
                }
 
                @Test
-               void onClassInfo() {
-                       var ci1 = ClassInfo.of(TargetClass1.class);
-                       var ci2 = ClassInfo.of(TargetClass2.class);
+               void c02_onClassInfo() {
+                       var ci1 = ClassInfo.of(TC.class);
+                       var ci2 = ClassInfo.of(TC2.class);
 
-                       var a = TestAppliedAnnotationObjectT.create()
-                               .on(ci1, ci2)
-                               .build();
+                       var a = C.create().on(ci1, ci2).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1",
-                               CNAME + "$TargetClass2"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC", CNAME + "$TC2");
                }
 
                @Test
-               void mixedTargeting() {
-                       var a = TestAppliedAnnotationObjectT.create()
-                               .on("com.example.StringTarget")
-                               .on(TargetClass1.class)
-                               .build();
+               void c03_mixedTargeting() {
+                       var a = 
C.create().on("com.example.StringTarget").on(TC.class).build();
 
-                       String[] expected = {
-                               "com.example.StringTarget",
-                               CNAME + "$TargetClass1"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), "com.example.StringTarget", CNAME + 
"$TC");
+               }
+
+               @Test
+               void c04_onClassClass() {
+                       var a = 
(AppliedOnClassAnnotationObject)C.create().onClass(TC.class, TC2.class).build();
+
+                       assertList(a.onClass(), TC.class, TC2.class);
+               }
+
+               @Test
+               void c05_onClassClassInfo() {
+                       var ci1 = ClassInfo.of(TC.class);
+                       var ci2 = ClassInfo.of(TC2.class);
+
+                       var a = 
(AppliedOnClassAnnotationObject)C.create().onClass(ci1, ci2).build();
+
+                       assertList(a.onClass(), TC.class, TC2.class);
                }
        }
 
        @Nested
        @DisplayName("BuilderM - Method targeting tests")
-       class BuilderMTests {
+       class D_BuilderMTests extends TestBase {
 
                /**
                 * Implementation with BuilderM for method targeting
                 */
-               public static class TestAppliedAnnotationObjectM extends 
AppliedAnnotationObject implements TestAppliedAnnotation {
+               public static class D extends AppliedAnnotationObject 
implements TA {
 
                        public static class Builder extends 
AppliedAnnotationObject.BuilderM {
 
                                public Builder() {
-                                       super(TestAppliedAnnotation.class);
+                                       super(TA.class);
                                }
 
                                @Override
@@ -373,8 +361,8 @@ class AppliedAnnotationObject_Test extends TestBase {
                                        return this;
                                }
 
-                               public TestAppliedAnnotation build() {
-                                       return new 
TestAppliedAnnotationObjectM(this);
+                               public TA build() {
+                                       return new D(this);
                                }
                        }
 
@@ -382,7 +370,7 @@ class AppliedAnnotationObject_Test extends TestBase {
                                return new Builder();
                        }
 
-                       public TestAppliedAnnotationObjectM(Builder b) {
+                       public D(Builder b) {
                                super(b);
                        }
 
@@ -398,51 +386,39 @@ class AppliedAnnotationObject_Test extends TestBase {
                }
 
                @Test
-               void onMethod() throws Exception {
-                       Method m1 = TargetClass1.class.getMethod("method1");
-                       Method m2 = TargetClass1.class.getMethod("method2", 
int.class);
+               void d01_onMethod() throws Exception {
+                       var m1 = TC.class.getMethod("method1");
+                       var m2 = TC.class.getMethod("method2", int.class);
 
-                       var a = TestAppliedAnnotationObjectM.create()
-                               .on(m1, m2)
-                               .build();
+                       var a = D.create().on(m1, m2).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1.method1()",
-                               CNAME + "$TargetClass1.method2(int)"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC.method1()", CNAME + 
"$TC.method2(int)");
                }
 
                @Test
-               void onMethodInfo() throws Exception {
-                       var mi1 = 
MethodInfo.of(TargetClass1.class.getMethod("method1"));
-                       var mi2 = 
MethodInfo.of(TargetClass1.class.getMethod("method2", int.class));
+               void d02_onMethodInfo() throws Exception {
+                       var mi1 = MethodInfo.of(TC.class.getMethod("method1"));
+                       var mi2 = MethodInfo.of(TC.class.getMethod("method2", 
int.class));
 
-                       var a = TestAppliedAnnotationObjectM.create()
-                               .on(mi1, mi2)
-                               .build();
+                       var a = D.create().on(mi1, mi2).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1.method1()",
-                               CNAME + "$TargetClass1.method2(int)"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC.method1()", CNAME + 
"$TC.method2(int)");
                }
        }
 
        @Nested
        @DisplayName("BuilderC - Constructor targeting tests")
-       class BuilderCTests {
+       class E_BuilderCTests extends TestBase {
 
                /**
                 * Implementation with BuilderC for constructor targeting
                 */
-               public static class TestAppliedAnnotationObjectC extends 
AppliedAnnotationObject implements TestAppliedAnnotation {
+               public static class E extends AppliedAnnotationObject 
implements TA {
 
                        public static class Builder extends 
AppliedAnnotationObject.BuilderC {
 
                                public Builder() {
-                                       super(TestAppliedAnnotation.class);
+                                       super(TA.class);
                                }
 
                                @Override
@@ -463,8 +439,8 @@ class AppliedAnnotationObject_Test extends TestBase {
                                        return this;
                                }
 
-                               public TestAppliedAnnotation build() {
-                                       return new 
TestAppliedAnnotationObjectC(this);
+                               public TA build() {
+                                       return new E(this);
                                }
                        }
 
@@ -472,7 +448,7 @@ class AppliedAnnotationObject_Test extends TestBase {
                                return new Builder();
                        }
 
-                       public TestAppliedAnnotationObjectC(Builder b) {
+                       public E(Builder b) {
                                super(b);
                        }
 
@@ -488,51 +464,39 @@ class AppliedAnnotationObject_Test extends TestBase {
                }
 
                @Test
-               void onConstructor() throws Exception {
-                       Constructor<?> c1 = TargetClass1.class.getConstructor();
-                       Constructor<?> c2 = 
TargetClass1.class.getConstructor(String.class);
+               void e01_onConstructor() throws Exception {
+                       var c1 = TC.class.getConstructor();
+                       var c2 = TC.class.getConstructor(String.class);
 
-                       var a = TestAppliedAnnotationObjectC.create()
-                               .on(c1, c2)
-                               .build();
+                       var a = E.create().on(c1, c2).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1()",
-                               CNAME + "$TargetClass1(java.lang.String)"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC()", CNAME + 
"$TC(java.lang.String)");
                }
 
                @Test
-               void onConstructorInfo() throws Exception {
-                       var ci1 = 
ConstructorInfo.of(TargetClass1.class.getConstructor());
-                       var ci2 = 
ConstructorInfo.of(TargetClass1.class.getConstructor(String.class));
+               void e02_onConstructorInfo() throws Exception {
+                       var ci1 = ConstructorInfo.of(TC.class.getConstructor());
+                       var ci2 = 
ConstructorInfo.of(TC.class.getConstructor(String.class));
 
-                       var a = TestAppliedAnnotationObjectC.create()
-                               .on(ci1, ci2)
-                               .build();
+                       var a = E.create().on(ci1, ci2).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1()",
-                               CNAME + "$TargetClass1(java.lang.String)"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC()", CNAME + 
"$TC(java.lang.String)");
                }
        }
 
        @Nested
        @DisplayName("BuilderMF - Method and Field targeting tests")
-       class BuilderMFTests {
+       class F_BuilderMFTests extends TestBase {
 
                /**
                 * Implementation with BuilderMF for method and field targeting
                 */
-               public static class TestAppliedAnnotationObjectMF extends 
AppliedAnnotationObject implements TestAppliedAnnotation {
+               public static class F extends AppliedAnnotationObject 
implements TA {
 
                        public static class Builder extends 
AppliedAnnotationObject.BuilderMF {
 
                                public Builder() {
-                                       super(TestAppliedAnnotation.class);
+                                       super(TA.class);
                                }
 
                                @Override
@@ -565,8 +529,8 @@ class AppliedAnnotationObject_Test extends TestBase {
                                        return this;
                                }
 
-                               public TestAppliedAnnotation build() {
-                                       return new 
TestAppliedAnnotationObjectMF(this);
+                               public TA build() {
+                                       return new F(this);
                                }
                        }
 
@@ -574,7 +538,7 @@ class AppliedAnnotationObject_Test extends TestBase {
                                return new Builder();
                        }
 
-                       public TestAppliedAnnotationObjectMF(Builder b) {
+                       public F(Builder b) {
                                super(b);
                        }
 
@@ -590,110 +554,422 @@ class AppliedAnnotationObject_Test extends TestBase {
                }
 
                @Test
-               void onField() throws Exception {
-                       Field f1 = TargetClass1.class.getField("field1");
-                       Field f2 = TargetClass1.class.getField("field2");
+               void f01_onField() throws Exception {
+                       var f1 = TC.class.getField("field1");
+                       var f2 = TC.class.getField("field2");
+
+                       var a = F.create().on(f1, f2).build();
+
+                       assertList(a.on(), CNAME + "$TC.field1", CNAME + 
"$TC.field2");
+               }
+
+               @Test
+               void f02_onFieldInfo() throws Exception {
+                       var fi1 = FieldInfo.of(ClassInfo.of(TC.class), 
TC.class.getField("field1"));
+                       var fi2 = FieldInfo.of(ClassInfo.of(TC.class), 
TC.class.getField("field2"));
+
+                       var a = F.create().on(fi1, fi2).build();
+
+                       assertList(a.on(), CNAME + "$TC.field1", CNAME + 
"$TC.field2");
+               }
+
+               @Test
+               void f03_mixedMethodsAndFields() throws Exception {
+                       var m = TC.class.getMethod("method1");
+                       var f = TC.class.getField("field1");
+
+                       var a = F.create().on(m).on(f).build();
+
+                       assertList(a.on(), CNAME + "$TC.method1()", CNAME + 
"$TC.field1");
+               }
+
+               @Test
+               void f04_onMethodInfo() throws Exception {
+                       var mi1 = MethodInfo.of(TC.class.getMethod("method1"));
+                       var mi2 = MethodInfo.of(TC.class.getMethod("method2", 
int.class));
+
+                       var a = F.create().on(mi1, mi2).build();
+
+                       assertList(a.on(), CNAME + "$TC.method1()", CNAME + 
"$TC.method2(int)");
+               }
+       }
+
+       @Nested
+       @DisplayName("BuilderTM - Class and Method targeting tests")
+       class G_BuilderTMTests extends TestBase {
+
+               /**
+                * Implementation with BuilderTM for class and method targeting
+                */
+               public static class G extends AppliedOnClassAnnotationObject 
implements TA {
+
+                       public static class Builder extends 
AppliedAnnotationObject.BuilderTM {
+
+                               public Builder() {
+                                       super(TA.class);
+                               }
+
+                               @Override
+                               public Builder on(String...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Class<?>...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(ClassInfo...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Method...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(MethodInfo...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder onClass(Class<?>...value) {
+                                       super.onClass(value);
+                                       return this;
+                               }
+
+                               public TA build() {
+                                       return new G(this);
+                               }
+                       }
+
+                       public static Builder create() {
+                               return new Builder();
+                       }
+
+                       public G(Builder b) {
+                               super(b);
+                       }
+
+                       @Override
+                       public String value() {
+                               return "";
+                       }
+
+                       @Override
+                       public int number() {
+                               return 0;
+                       }
+               }
+
+               @Test
+               void g01_onClassAndMethod() throws Exception {
+                       var m = TC.class.getMethod("method1");
+
+                       var a = G.create().on(TC.class).on(m).build();
+
+                       assertList(a.on(), CNAME + "$TC", CNAME + 
"$TC.method1()");
+               }
+
+               @Test
+               void g02_onMethodInfo() throws Exception {
+                       var mi = MethodInfo.of(TC.class.getMethod("method1"));
+
+                       var a = G.create().on(mi).build();
+
+                       assertList(a.on(), CNAME + "$TC.method1()");
+               }
+
+               @Test
+               void g03_onClassClass() {
+                       var a = (AppliedOnClassAnnotationObject) 
G.create().onClass(TC.class, TC2.class).build();
+
+                       assertList(a.onClass(), TC.class, TC2.class);
+               }
+       }
+
+       @Nested
+       @DisplayName("BuilderTMF - Class, Method, and Field targeting tests")
+       class H_BuilderTMFTests extends TestBase {
+
+               /**
+                * Implementation with BuilderTMF for class, method, and field 
targeting
+                */
+               public static class H extends AppliedOnClassAnnotationObject 
implements TA {
+
+                       public static class Builder extends 
AppliedAnnotationObject.BuilderTMF {
+
+                               public Builder() {
+                                       super(TA.class);
+                               }
+
+                               @Override
+                               public Builder on(String...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Class<?>...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(ClassInfo...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Method...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(MethodInfo...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Field...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(FieldInfo...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               public TA build() {
+                                       return new H(this);
+                               }
+                       }
+
+                       public static Builder create() {
+                               return new Builder();
+                       }
+
+                       public H(Builder b) {
+                               super(b);
+                       }
+
+                       @Override
+                       public String value() {
+                               return "";
+                       }
+
+                       @Override
+                       public int number() {
+                               return 0;
+                       }
+               }
+
+               @Test
+               void h01_onClassMethodAndField() throws Exception {
+                       var m = TC.class.getMethod("method1");
+                       var f = TC.class.getField("field1");
+
+                       var a = H.create().on(TC.class).on(m).on(f).build();
+
+                       assertList(a.on(), CNAME + "$TC", CNAME + 
"$TC.method1()", CNAME + "$TC.field1");
+               }
+
+               @Test
+               void h02_onMethodInfo() throws Exception {
+                       var mi = MethodInfo.of(TC.class.getMethod("method1"));
+
+                       var a = H.create().on(mi).build();
+
+                       assertList(a.on(), CNAME + "$TC.method1()");
+               }
+
+               @Test
+               void h03_onFieldInfo() throws Exception {
+                       var fi = FieldInfo.of(ClassInfo.of(TC.class), 
TC.class.getField("field1"));
+
+                       var a = H.create().on(fi).build();
+
+                       assertList(a.on(), CNAME + "$TC.field1");
+               }
+       }
+
+       @Nested
+       @DisplayName("BuilderTMFC - Class, Method, Field, and Constructor 
targeting tests")
+       class I_BuilderTMFCTests extends TestBase {
+
+               /**
+                * Implementation with BuilderTMFC for complete targeting
+                */
+               public static class I extends AppliedOnClassAnnotationObject 
implements TA {
+
+                       public static class Builder extends 
AppliedAnnotationObject.BuilderTMFC {
+
+                               public Builder() {
+                                       super(TA.class);
+                               }
+
+                               @Override
+                               public Builder on(String...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Class<?>...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Method...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(MethodInfo...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Field...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(FieldInfo...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(Constructor<?>...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               @Override
+                               public Builder on(ConstructorInfo...value) {
+                                       super.on(value);
+                                       return this;
+                               }
+
+                               public TA build() {
+                                       return new I(this);
+                               }
+                       }
+
+                       public static Builder create() {
+                               return new Builder();
+                       }
+
+                       public I(Builder b) {
+                               super(b);
+                       }
+
+                       @Override
+                       public String value() {
+                               return "";
+                       }
+
+                       @Override
+                       public int number() {
+                               return 0;
+                       }
+               }
+
+               @Test
+               void i01_onAllTypes() throws Exception {
+                       var m = TC.class.getMethod("method1");
+                       var f = TC.class.getField("field1");
+                       var c = TC.class.getConstructor();
+
+                       var a = 
I.create().on(TC.class).on(m).on(f).on(c).build();
+
+                       assertList(a.on(), CNAME + "$TC", CNAME + 
"$TC.method1()", CNAME + "$TC.field1", CNAME + "$TC()");
+               }
+
+               @Test
+               void i02_onMethodInfo() throws Exception {
+                       var mi = MethodInfo.of(TC.class.getMethod("method1"));
 
-                       var a = TestAppliedAnnotationObjectMF.create()
-                               .on(f1, f2)
-                               .build();
+                       var a = I.create().on(mi).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1.field1",
-                               CNAME + "$TargetClass1.field2"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC.method1()");
                }
 
                @Test
-               void onFieldInfo() throws Exception {
-                       var fi1 = 
FieldInfo.of(ClassInfo.of(TargetClass1.class), 
TargetClass1.class.getField("field1"));
-                       var fi2 = 
FieldInfo.of(ClassInfo.of(TargetClass1.class), 
TargetClass1.class.getField("field2"));
+               void i03_onFieldInfo() throws Exception {
+                       var fi = FieldInfo.of(ClassInfo.of(TC.class), 
TC.class.getField("field1"));
 
-                       var a = TestAppliedAnnotationObjectMF.create()
-                               .on(fi1, fi2)
-                               .build();
+                       var a = I.create().on(fi).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1.field1",
-                               CNAME + "$TargetClass1.field2"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC.field1");
                }
 
                @Test
-               void mixedMethodsAndFields() throws Exception {
-                       Method m = TargetClass1.class.getMethod("method1");
-                       Field f = TargetClass1.class.getField("field1");
+               void i04_onConstructorInfo() throws Exception {
+                       var ci = 
ConstructorInfo.of(TC.class.getConstructor(String.class));
 
-                       var a = TestAppliedAnnotationObjectMF.create()
-                               .on(m)
-                               .on(f)
-                               .build();
+                       var a = I.create().on(ci).build();
 
-                       String[] expected = {
-                               CNAME + "$TargetClass1.method1()",
-                               CNAME + "$TargetClass1.field1"
-                       };
-                       assertArrayEquals(expected, a.on());
+                       assertList(a.on(), CNAME + "$TC(java.lang.String)");
                }
        }
 
        @Nested
        @DisplayName("Fluent API tests")
-       class FluentApiTests {
+       class J_FluentApiTests extends TestBase {
 
                @Test
-               void chaining() {
-                       var a = TestAppliedAnnotationObject.create()
-                               .on("target1")
-                               .value("test")
-                               .on("target2")
-                               .number(42)
-                               .on("target3")
-                               .build();
+               void j01_chaining() {
+                       var a = 
TAO.create().on("target1").value("test").on("target2").number(42).on("target3").build();
 
-                       assertArrayEquals(new String[]{"target1", "target2", 
"target3"}, a.on());
-                       assertEquals("test", a.value());
-                       assertEquals(42, a.number());
+                       assertBean(a, "on,value,number", 
"[target1,target2,target3],test,42");
                }
        }
 
        @Nested
        @DisplayName("toMap() tests")
-       class ToMapTests {
+       class K_ToMapTests extends TestBase {
 
                @Test
-               void withTargets() {
-                       var a = TestAppliedAnnotationObject.create()
-                               .on("target1", "target2")
-                               .value("test")
-                               .build();
+               void k01_withTargets() {
+                       var a = TAO.create().on("target1", 
"target2").value("test").build();
 
-                       var map = ((TestAppliedAnnotationObject)a).toMap();
-                       assertArrayEquals(new String[]{"target1", "target2"}, 
(String[])map.get("on"));
-                       assertEquals("test", map.get("value"));
+                       var map = ((TAO)a).toMap();
+                       assertBean(map, "on,value", "[target1,target2],test");
                }
        }
 
        @Nested
        @DisplayName("Edge case tests")
-       class EdgeCaseTests {
+       class L_EdgeCaseTests extends TestBase {
 
                @Test
-               void emptyTargets() {
-                       var a = TestAppliedAnnotationObject.create()
-                               .on()
-                               .build();
+               void l01_emptyTargets() {
+                       var a = TAO.create().on().build();
 
-                       assertArrayEquals(new String[0], a.on());
+                       assertList(a.on());
                }
 
                @Test
-               void builderReuse() {
-                       var builder = TestAppliedAnnotationObject.create()
-                               .on("target1")
-                               .value("test");
+               void l02_builderReuse() {
+                       var builder = TAO.create().on("target1").value("test");
 
                        var a1 = builder.build();
                        var a2 = builder.build();
@@ -706,78 +982,46 @@ class AppliedAnnotationObject_Test extends TestBase {
 
        @Nested
        @DisplayName("Null validation tests")
-       class NullValidationTests {
+       class M_NullValidationTests extends TestBase {
 
                @Test
-               void nullClass_throwsException() {
-                       assertThrows(IllegalArgumentException.class, () ->
-                               
BuilderTTests.TestAppliedAnnotationObjectT.create()
-                                       .on((Class<?>)null)
-                                       .build()
-                       );
+               void m01_nullClass_throwsException() {
+                       assertThrows(IllegalArgumentException.class, () -> 
C_BuilderTTests.C.create().on((Class<?>)null).build());
                }
 
                @Test
-               void nullClassInfo_throwsException() {
-                       assertThrows(IllegalArgumentException.class, () ->
-                               
BuilderTTests.TestAppliedAnnotationObjectT.create()
-                                       .on((ClassInfo)null)
-                                       .build()
-                       );
+               void m02_nullClassInfo_throwsException() {
+                       assertThrows(IllegalArgumentException.class, () -> 
C_BuilderTTests.C.create().on((ClassInfo)null).build());
                }
 
                @Test
-               void nullMethod_throwsException() {
-                       assertThrows(IllegalArgumentException.class, () ->
-                               
BuilderMTests.TestAppliedAnnotationObjectM.create()
-                                       .on((java.lang.reflect.Method)null)
-                                       .build()
-                       );
+               void m03_nullMethod_throwsException() {
+                       assertThrows(IllegalArgumentException.class, () -> 
D_BuilderMTests.D.create().on((java.lang.reflect.Method)null).build());
                }
 
                @Test
-               void nullMethodInfo_throwsException() {
-                       assertThrows(IllegalArgumentException.class, () ->
-                               
BuilderMTests.TestAppliedAnnotationObjectM.create()
-                                       .on((MethodInfo)null)
-                                       .build()
-                       );
+               void m04_nullMethodInfo_throwsException() {
+                       assertThrows(IllegalArgumentException.class, () -> 
D_BuilderMTests.D.create().on((MethodInfo)null).build());
                }
 
                @Test
-               void nullField_throwsException() {
-                       assertThrows(IllegalArgumentException.class, () ->
-                               
BuilderMFTests.TestAppliedAnnotationObjectMF.create()
-                                       .on((java.lang.reflect.Field)null)
-                                       .build()
-                       );
+               void m05_nullField_throwsException() {
+                       assertThrows(IllegalArgumentException.class, () -> 
F_BuilderMFTests.F.create().on((java.lang.reflect.Field)null).build());
                }
 
                @Test
-               void nullFieldInfo_throwsException() {
-                       assertThrows(IllegalArgumentException.class, () ->
-                               
BuilderMFTests.TestAppliedAnnotationObjectMF.create()
-                                       .on((FieldInfo)null)
-                                       .build()
-                       );
+               void m06_nullFieldInfo_throwsException() {
+                       assertThrows(IllegalArgumentException.class, () -> 
F_BuilderMFTests.F.create().on((FieldInfo)null).build());
                }
 
                @Test
-               void nullConstructor_throwsException() {
-                       assertThrows(IllegalArgumentException.class, () ->
-                               
BuilderCTests.TestAppliedAnnotationObjectC.create()
-                                       
.on((java.lang.reflect.Constructor<?>)null)
-                                       .build()
-                       );
+               void m07_nullConstructor_throwsException() {
+                       assertThrows(IllegalArgumentException.class, () -> 
E_BuilderCTests.E.create().on((java.lang.reflect.Constructor<?>)null).build());
                }
 
                @Test
-               void nullConstructorInfo_throwsException() {
-                       assertThrows(IllegalArgumentException.class, () ->
-                               
BuilderCTests.TestAppliedAnnotationObjectC.create()
-                                       .on((ConstructorInfo)null)
-                                       .build()
-                       );
+               void m08_nullConstructorInfo_throwsException() {
+                       assertThrows(IllegalArgumentException.class, () -> 
E_BuilderCTests.E.create().on((ConstructorInfo)null).build());
                }
        }
 }
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AppliedOnClassAnnotationObject_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AppliedOnClassAnnotationObject_Test.java
new file mode 100644
index 0000000000..8ad615e18b
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/common/annotation/AppliedOnClassAnnotationObject_Test.java
@@ -0,0 +1,417 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.common.annotation;
+
+import static org.apache.juneau.junit.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.common.reflect.*;
+import org.junit.jupiter.api.*;
+
+class AppliedOnClassAnnotationObject_Test extends TestBase {
+
+       private static final String CNAME = 
AppliedOnClassAnnotationObject_Test.class.getName();
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Test annotation for testing purposes
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Target({ ElementType.TYPE })
+       @Retention(RetentionPolicy.RUNTIME)
+       public @interface TA {
+               String[] on() default {};
+
+               Class<?>[] onClass() default {};
+
+               String value() default "";
+       }
+
+       /**
+        * Implementation of TA using AppliedOnClassAnnotationObject
+        */
+       public static class T extends AppliedOnClassAnnotationObject implements 
TA {
+
+               private final String value;
+
+               public static class Builder extends 
AppliedAnnotationObject.BuilderT {
+                       String value = "";
+
+                       public Builder() {
+                               super(TA.class);
+                       }
+
+                       public Builder value(String value) {
+                               this.value = value;
+                               return this;
+                       }
+
+                       @Override
+                       public Builder on(String...value) {
+                               super.on(value);
+                               return this;
+                       }
+
+                       @Override
+                       public Builder on(Class<?>...value) {
+                               super.on(value);
+                               return this;
+                       }
+
+                       @Override
+                       public Builder on(ClassInfo...value) {
+                               super.on(value);
+                               return this;
+                       }
+
+                       @Override
+                       public Builder onClass(Class<?>...value) {
+                               super.onClass(value);
+                               return this;
+                       }
+
+                       @Override
+                       public Builder onClass(ClassInfo...value) {
+                               super.onClass(value);
+                               return this;
+                       }
+
+                       public TA build() {
+                               return new T(this);
+                       }
+               }
+
+               public static Builder create() {
+                       return new Builder();
+               }
+
+               public T(Builder b) {
+                       super(b);
+                       value = b.value;
+               }
+
+               @Override
+               public String value() {
+                       return value;
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Test classes for targeting
+       
//------------------------------------------------------------------------------------------------------------------
+
+       public static class TC1 {}
+
+       public static class TC2 {}
+
+       public static class TC3 {}
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void a01_basic_noOnClass() {
+               var a = T.create().build();
+               assertList(a.onClass());
+       }
+
+       @Test
+       void a02_basic_singleClass() {
+               var a = T.create().onClass(TC1.class).build();
+
+               assertList(a.onClass(), TC1.class);
+       }
+
+       @Test
+       void a03_basic_multipleClasses() {
+               var a = T.create().onClass(TC1.class, TC2.class).build();
+
+               assertList(a.onClass(), TC1.class, TC2.class);
+       }
+
+       @Test
+       void a04_basic_withValue() {
+               var a = T.create().onClass(TC1.class).value("test").build();
+
+               assertList(a.onClass(), TC1.class);
+               assertEquals("test", a.value());
+       }
+
+       @Test
+       void a05_basic_annotationType() {
+               var a = T.create().build();
+               assertEquals(TA.class, a.annotationType());
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // on() vs onClass() tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void b01_onVsOnClass_onClassOnly() {
+               var a = T.create().onClass(TC1.class, TC2.class).build();
+
+               // onClass() returns the Class objects
+               assertList(a.onClass(), TC1.class, TC2.class);
+
+               // on() should be empty when only onClass() is used
+               assertList(a.on());
+       }
+
+       @Test
+       void b02_onVsOnClass_onOnly() {
+               var a = T.create().on("com.example.Class1", 
"com.example.Class2").build();
+
+               // on() returns the string targets
+               assertList(a.on(), "com.example.Class1", "com.example.Class2");
+
+               // onClass() should be empty when only on() is used
+               assertList(a.onClass());
+       }
+
+       @Test
+       void b03_onVsOnClass_both() {
+               var a = 
T.create().on("com.example.Class1").onClass(TC1.class).build();
+
+               // Both should be independent
+               assertList(a.on(), "com.example.Class1");
+               assertList(a.onClass(), TC1.class);
+       }
+
+       @Test
+       void b04_onVsOnClass_onWithClassConversion() {
+               var a = T.create().on(TC1.class, TC2.class).build();
+
+               // on(Class...) converts to strings
+               assertList(a.on(), CNAME + "$TC1", CNAME + "$TC2");
+
+               // onClass() should be empty since we used on(Class...) not 
onClass(Class...)
+               assertList(a.onClass());
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // ClassInfo tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void c01_classInfo_onClassInfo() {
+               var ci1 = ClassInfo.of(TC1.class);
+               var ci2 = ClassInfo.of(TC2.class);
+
+               var a = T.create().onClass(ci1, ci2).build();
+
+               assertList(a.onClass(), TC1.class, TC2.class);
+       }
+
+       @Test
+       void c02_classInfo_onClassInfo_mixed() {
+               var ci = ClassInfo.of(TC1.class);
+
+               var a = T.create().onClass(ci).onClass(TC2.class).build();
+
+               assertList(a.onClass(), TC1.class, TC2.class);
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Equality and hashcode tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void d01_equality_sameOnClass() {
+               var a1 = T.create().onClass(TC1.class, 
TC2.class).value("test").build();
+
+               var a2 = T.create().onClass(TC1.class, 
TC2.class).value("test").build();
+
+               assertEquals(a1, a2);
+               assertEquals(a1.hashCode(), a2.hashCode());
+       }
+
+       @Test
+       void d02_equality_differentOnClass() {
+               var a1 = T.create().onClass(TC1.class).build();
+
+               var a2 = T.create().onClass(TC2.class).build();
+
+               assertNotEquals(a1, a2);
+       }
+
+       @Test
+       void d03_equality_differentOrder() {
+               var a1 = T.create().onClass(TC1.class, TC2.class).build();
+
+               var a2 = T.create().onClass(TC2.class, TC1.class).build();
+
+               assertNotEquals(a1, a2);
+       }
+
+       @Test
+       void d04_equality_withDeclaredAnnotation() {
+               @TA(onClass = { TC1.class, TC2.class }, value = "test")
+               class TestClass {}
+
+               var declared = TestClass.class.getAnnotation(TA.class);
+               var programmatic = T.create().onClass(TC1.class, 
TC2.class).value("test").build();
+
+               assertEquals(declared, programmatic);
+               assertEquals(declared.hashCode(), programmatic.hashCode());
+       }
+
+       @Test
+       void d05_hashCode_consistency() {
+               var a = T.create().onClass(TC1.class).value("test").build();
+
+               var hash1 = a.hashCode();
+               var hash2 = a.hashCode();
+               assertEquals(hash1, hash2, "hashCode should be consistent");
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // toMap() tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void e01_toMap_withOnClass() {
+               var a = T.create().onClass(TC1.class, 
TC2.class).value("test").build();
+               var map = ((T)a).toMap();
+
+               assertBean(map, "value,on,onClass", "test,[],[TC1,TC2]");
+       }
+
+       @Test
+       void e02_toMap_withBoth() {
+               var a = 
T.create().on("com.example.Class1").onClass(TC1.class).value("test").build();
+               var map = ((T)a).toMap();
+
+               assertBean(map, "value,on,onClass", 
"test,[com.example.Class1],[TC1]");
+       }
+
+       @Test
+       void e03_toMap_empty() {
+               var a = T.create().build();
+               var map = ((T)a).toMap();
+
+               assertBean(map, "value,on,onClass", ",[],[]");
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // toString() tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void f01_toString_notNull() {
+               var a = T.create().build();
+               var str = a.toString();
+               assertNotNull(str);
+               assertFalse(str.isEmpty());
+       }
+
+       @Test
+       void f02_toString_containsValues() {
+               var a = T.create().onClass(TC1.class).value("test").build();
+
+               assertContainsAll(a.toString(), "test", "onClass");
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Builder pattern tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void g01_builder_fluentApi() {
+               var a = 
T.create().onClass(TC1.class).value("test").onClass(TC2.class).build();
+
+               assertList(a.onClass(), TC1.class, TC2.class);
+               assertEquals("test", a.value());
+       }
+
+       @Test
+       void g02_builder_multipleBuilds() {
+               var builder = T.create().onClass(TC1.class).value("test");
+
+               var a1 = builder.build();
+               var a2 = builder.build();
+
+               // Different instances but equal
+               assertNotSame(a1, a2);
+               assertEquals(a1, a2);
+       }
+
+       @Test
+       void g03_builder_chaining() {
+               var a = 
T.create().onClass(TC1.class).on("com.example.Class1").value("test").onClass(TC2.class).build();
+
+               assertList(a.onClass(), TC1.class, TC2.class);
+               assertList(a.on(), "com.example.Class1");
+               assertEquals("test", a.value());
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Edge cases
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void h01_edgeCase_emptyOnClass() {
+               var a = T.create().onClass(new Class<?>[0]).build();
+
+               assertList(a.onClass());
+       }
+
+       @Test
+       void h02_edgeCase_arrayEquality() {
+               var a1 = T.create().onClass(TC1.class, TC2.class, 
TC3.class).build();
+
+               var a2 = T.create().onClass(new Class<?>[] { TC1.class, 
TC2.class, TC3.class }).build();
+
+               assertEquals(a1, a2);
+       }
+
+       @Test
+       void h03_edgeCase_equality_differentType() {
+               var a = T.create().build();
+               var other = new Object();
+
+               assertNotEquals(a, other);
+       }
+
+       @Test
+       void h04_edgeCase_equality_null() {
+               var a = T.create().build();
+               assertNotEquals(a, null);
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Null validation tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void i01_null_classInArray() {
+               assertThrows(IllegalArgumentException.class, () -> 
T.create().onClass((Class<?>)null).build());
+       }
+
+       @Test
+       void i02_null_classInfoInArray() {
+               assertThrows(IllegalArgumentException.class, () -> 
T.create().onClass((ClassInfo)null).build());
+       }
+
+       @Test
+       void i03_null_builder() {
+               assertThrows(IllegalArgumentException.class, () -> new T(null));
+       }
+}

Reply via email to