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));
+ }
+}