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 0a3c1632b8 New BeanCreator API
0a3c1632b8 is described below
commit 0a3c1632b88698109b36ef1e6c9d2e9f0619f57c
Author: James Bognar <[email protected]>
AuthorDate: Wed Jan 21 11:33:03 2026 -0500
New BeanCreator API
---
.../juneau/commons/reflect/AnnotationInfo.java | 24 ++++++--
.../apache/juneau/commons/reflect/ClassInfo.java | 4 +-
.../apache/juneau/commons/reflect/FieldInfo.java | 2 +-
.../juneau/commons/reflect/ParameterInfo.java | 6 +-
.../rest/client/remote/RemoteOperationMeta.java | 2 +-
.../commons/reflect/AnnotationInfo_Test.java | 44 ++++++++++----
.../juneau/commons/reflect/FieldInfo_Test.java | 70 +++++++++++-----------
7 files changed, 94 insertions(+), 58 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java
index a2d16d6d40..4de6c1ffd5 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java
@@ -402,18 +402,32 @@ public class AnnotationInfo<T extends Annotation> {
// Private helper methods
//-----------------------------------------------------------------------------------------------------------------
+ /**
+ * Returns the class name of this annotation.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * AnnotationInfo<MyAnnotation> <jv>ai</jv> = ...;
+ * String <jv>name</jv> = <jv>ai</jv>.getName(); <jc>// Returns
"mypackage.MyAnnotation"</jc>
+ * </p>
+ *
+ * @return The simple class name of the annotation (e.g., {@code
"Override"} for {@code @Override}).
+ */
+ public String getName() { return cn(a.annotationType()); }
+
/**
* Returns the simple class name of this annotation.
*
* <h5 class='section'>Example:</h5>
* <p class='bjava'>
* AnnotationInfo<MyAnnotation> <jv>ai</jv> = ...;
- * String <jv>name</jv> = <jv>ai</jv>.getName(); <jc>// Returns
"MyAnnotation"</jc>
+ * String <jv>name</jv> = <jv>ai</jv>.getNameSimple(); <jc>//
Returns "MyAnnotation"</jc>
* </p>
*
* @return The simple class name of the annotation (e.g., {@code
"Override"} for {@code @Override}).
+ * @see #getName()
*/
- public String getName() { return cns(a.annotationType()); }
+ public String getNameSimple() { return cns(a.annotationType()); }
/**
* Returns the rank of this annotation for sorting by precedence.
@@ -591,7 +605,7 @@ public class AnnotationInfo<T extends Annotation> {
* @return <jk>true</jk> if this annotation has the specified
fully-qualified name.
*/
public boolean hasName(String value) {
- return eq(value, a.annotationType().getName());
+ return eq(value, getName());
}
/**
@@ -605,8 +619,8 @@ public class AnnotationInfo<T extends Annotation> {
* @param value The simple name to check.
* @return <jk>true</jk> if this annotation has the specified simple
name.
*/
- public boolean hasSimpleName(String value) {
- return eq(value, a.annotationType().getSimpleName());
+ public boolean hasNameSimple(String value) {
+ return eq(value, getNameSimple());
}
/**
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
index 624e87c356..e89d7e5fb9 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
@@ -2819,12 +2819,12 @@ public class ClassInfo extends ElementInfo implements
Annotatable, Type, Compara
public <T> T inject(T bean, BeanStore beanStore) {
// Inject into fields
getAllFields().stream()
- .filter(x -> x.isNotFinal() &&
x.getAnnotations().stream().map(AnnotationInfo::getName).anyMatch(n -> eq(n,
"Inject") || eq(n, "Autowired")))
+ .filter(x -> x.isNotFinal() &&
x.getAnnotations().stream().map(AnnotationInfo::getNameSimple).anyMatch(n ->
eq(n, "Inject") || eq(n, "Autowired")))
.forEach(x -> x.inject(beanStore, bean));
// Inject into methods
getAllMethods().stream()
- .filter(x -> x.isNotAbstract() &&
eq(x.getTypeParameters().length, 0) &&
x.getAnnotations().stream().map(AnnotationInfo::getName).anyMatch(n -> eq(n,
"Inject") || eq(n, "Autowired")))
+ .filter(x -> x.isNotAbstract() &&
eq(x.getTypeParameters().length, 0) &&
x.getAnnotations().stream().map(AnnotationInfo::getNameSimple).anyMatch(n ->
eq(n, "Inject") || eq(n, "Autowired")))
.forEach(x -> x.inject(beanStore, bean));
return bean;
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/FieldInfo.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/FieldInfo.java
index a6ea07b7b7..f3b988e3f1 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/FieldInfo.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/FieldInfo.java
@@ -585,7 +585,7 @@ public class FieldInfo extends AccessibleInfo implements
Comparable<FieldInfo>,
// Find qualifier from @Named or @Qualifier annotation (same
logic as ParameterInfo.getResolvedQualifier)
var beanQualifier = getAnnotations().stream()
- .filter(ai -> ai.hasSimpleName("Named") ||
ai.hasSimpleName("Qualifier"))
+ .filter(ai -> ai.hasNameSimple("Named") ||
ai.hasNameSimple("Qualifier"))
.map(ai -> ai.getValue().orElse(null))
.filter(Objects::nonNull)
.findFirst()
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ParameterInfo.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ParameterInfo.java
index e8af8326e8..dae538a0ac 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ParameterInfo.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ParameterInfo.java
@@ -667,7 +667,7 @@ public class ParameterInfo extends ElementInfo implements
Annotatable {
// Parameter type (use generic type if available to show
generics)
var paramType = getParameterizedType();
-
+
// For varargs, we need to get the component type and display
it with "..." instead of "[]"
if (isVarArgs()) {
// Get the component type of the array
@@ -732,7 +732,7 @@ public class ParameterInfo extends ElementInfo implements
Annotatable {
// because bytecode names are unreliable - users may or may not
compile with -parameters flag.
for (var mp : getMatchingParameters()) {
for (var ai : mp.getAnnotations()) {
- if (ai.hasSimpleName("Name")) {
+ if (ai.hasNameSimple("Name")) {
var value = ai.getValue().orElse(null);
if (value != null) // HTT
return value;
@@ -748,7 +748,7 @@ public class ParameterInfo extends ElementInfo implements
Annotatable {
// @formatter:off
return getMatchingParameters().stream()
.flatMap(mp -> mp.getAnnotations().stream())
- .filter(ai -> ai.hasSimpleName("Named") ||
ai.hasSimpleName("Qualifier"))
+ .filter(ai -> ai.hasNameSimple("Named") ||
ai.hasNameSimple("Qualifier"))
.map(ai -> ai.getValue().orElse(null))
.filter(Objects::nonNull)
.findFirst()
diff --git
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationMeta.java
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationMeta.java
index 80da93a45a..63937ed113 100644
---
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationMeta.java
+++
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationMeta.java
@@ -69,7 +69,7 @@ public class RemoteOperationMeta {
var _httpMethod = Value.<String>empty();
var _path = Value.<String>empty();
- al.stream().map(x ->
x.getName().substring(6).toUpperCase()).filter(x -> ! x.equals("OP")).forEach(x
-> _httpMethod.set(x));
+ al.stream().map(x ->
x.getNameSimple().substring(6).toUpperCase()).filter(x -> !
x.equals("OP")).forEach(x -> _httpMethod.set(x));
al.forEach(ai -> ai.getValue(String.class,
"method").filter(NOT_EMPTY).ifPresent(x ->
_httpMethod.set(x.trim().toUpperCase())));
al.forEach(ai -> ai.getValue(String.class,
"path").filter(NOT_EMPTY).ifPresent(x -> _path.set(x.trim())));
httpMethod = _httpMethod.orElse("").trim();
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/AnnotationInfo_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/AnnotationInfo_Test.java
index 1766e4734c..3f97f9e56e 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/AnnotationInfo_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/AnnotationInfo_Test.java
@@ -387,7 +387,29 @@ class AnnotationInfo_Test extends TestBase {
var ci = ClassInfo.of(TestClass.class);
var ai =
ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
assertNotNull(ai);
- assertEquals("TestAnnotation", ai.getName());
+ // getName() now returns fully qualified name
+
assertEquals("org.apache.juneau.commons.reflect.AnnotationInfo_Test$TestAnnotation",
ai.getName());
+ }
+
+ @Test
+ void a015_getNameSimple() {
+ var ci = ClassInfo.of(TestClass.class);
+ var ai =
ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
+ assertNotNull(ai);
+ // getNameSimple() returns simple name
+ assertEquals("TestAnnotation", ai.getNameSimple());
+
+ // Test with standard library annotation
+ var ci2 = ClassInfo.of(DocumentedClass.class);
+ var ai2 =
ci2.getAnnotations(DocumentedAnnotation.class).findFirst().orElse(null);
+ assertNotNull(ai2);
+ assertEquals("DocumentedAnnotation", ai2.getNameSimple());
+
+ // Test with nested annotation
+ var ci3 = ClassInfo.of(GroupTestClass.class);
+ var ai3 =
ci3.getAnnotations(GroupMember1.class).findFirst().orElse(null);
+ assertNotNull(ai3);
+ assertEquals("GroupMember1", ai3.getNameSimple());
}
//====================================================================================================
@@ -551,8 +573,8 @@ class AnnotationInfo_Test extends TestBase {
var ai =
ci.getAnnotations(TestAnnotation.class).findFirst().orElse(null);
assertNotNull(ai);
- assertTrue(ai.hasSimpleName("TestAnnotation"));
- assertFalse(ai.hasSimpleName(TestAnnotation.class.getName()));
+ assertTrue(ai.hasNameSimple("TestAnnotation"));
+ assertFalse(ai.hasNameSimple(TestAnnotation.class.getName()));
}
//====================================================================================================
@@ -660,16 +682,16 @@ class AnnotationInfo_Test extends TestBase {
assertNotNull(map2);
var annotationMap2 =
(java.util.Map<String,Object>)map2.get("@ToMapTestAnnotation");
assertNotNull(annotationMap2);
-
+
// value differs from default (non-array), should be included
assertEquals("custom", annotationMap2.get("value"));
-
+
// nonEmptyArray differs from default (non-empty array), should
be included
assertTrue(annotationMap2.containsKey("nonEmptyArray"));
-
+
// emptyArrayWithNonEmptyDefault is empty array but default is
non-empty, should be included
assertTrue(annotationMap2.containsKey("emptyArrayWithNonEmptyDefault"));
-
+
// arrayValue is empty array matching default empty array,
should NOT be included
assertFalse(annotationMap2.containsKey("arrayValue"));
@@ -696,21 +718,21 @@ class AnnotationInfo_Test extends TestBase {
return method.getDefaultValue();
}
};
-
+
var proxyAnnotation =
(ToMapTestAnnotation)java.lang.reflect.Proxy.newProxyInstance(
annotationType.getClassLoader(),
new Class[]{annotationType},
handler
);
-
+
var ci3 = ClassInfo.of(ToMapTestClass.class);
var ai3 = AnnotationInfo.of(ci3, proxyAnnotation);
-
+
var map3 = ai3.properties();
assertNotNull(map3);
var annotationMap3 =
(java.util.Map<String,Object>)map3.get("@ToMapTestAnnotation");
assertNotNull(annotationMap3);
-
+
// The exception should be caught and stored as a localized
message
assertTrue(annotationMap3.containsKey("value"));
var value = annotationMap3.get("value");
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/FieldInfo_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/FieldInfo_Test.java
index 378d981b24..4cfaf3d0f5 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/FieldInfo_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/FieldInfo_Test.java
@@ -209,7 +209,7 @@ class FieldInfo_Test extends TestBase {
assertDoesNotThrow(()->d_isProtected.accessible());
assertDoesNotThrow(()->d_isPrivate.accessible());
assertDoesNotThrow(()->d_isDefault.accessible());
-
+
// Verify it returns this for chaining
var result = d_isPublic.accessible();
assertSame(d_isPublic, result);
@@ -223,12 +223,12 @@ class FieldInfo_Test extends TestBase {
// Fields should be sorted by field name only
// "a2" comes before "f1" alphabetically, so b_a2 should come
before a1_f1
var b_a2 = off(B.class, "a2");
-
+
// "a2" < "f1" alphabetically, so b_a2 should come before a1_f1
assertTrue(b_a2.compareTo(a1_f1) < 0);
assertTrue(a1_f1.compareTo(b_a2) > 0);
assertEquals(0, a1_f1.compareTo(a1_f1));
-
+
// Test fields from same class - should be sorted by field name
assertTrue(b_a1.compareTo(b_a2) < 0);
assertTrue(b_a2.compareTo(b_a1) > 0);
@@ -242,10 +242,10 @@ class FieldInfo_Test extends TestBase {
var obj = new GetSetTest();
obj.value = "test";
obj.number = 42;
-
+
assertEquals("test", getSetTest_value.get(obj));
assertEquals(Integer.valueOf(42), getSetTest_number.get(obj));
-
+
// Null value
obj.value = null;
assertNull(getSetTest_value.get(obj));
@@ -276,16 +276,16 @@ class FieldInfo_Test extends TestBase {
void a006_getAnnotations() {
var annotations1 = f_field1.getAnnotations();
assertEquals(2, annotations1.size());
- assertTrue(annotations1.stream().anyMatch(a ->
a.hasSimpleName("TestAnnotation1")));
- assertTrue(annotations1.stream().anyMatch(a ->
a.hasSimpleName("TestAnnotation2")));
+ assertTrue(annotations1.stream().anyMatch(a ->
a.hasNameSimple("TestAnnotation1")));
+ assertTrue(annotations1.stream().anyMatch(a ->
a.hasNameSimple("TestAnnotation2")));
var annotations2 = f_field2.getAnnotations();
assertEquals(1, annotations2.size());
- assertTrue(annotations2.stream().anyMatch(a ->
a.hasSimpleName("TestAnnotation1")));
+ assertTrue(annotations2.stream().anyMatch(a ->
a.hasNameSimple("TestAnnotation1")));
var annotations3 = f_field3.getAnnotations();
assertEquals(0, annotations3.size());
-
+
// Test memoization - should return same instance
var annotations1_2 = f_field1.getAnnotations();
assertSame(annotations1, annotations1_2);
@@ -331,7 +331,7 @@ class FieldInfo_Test extends TestBase {
void a009_getFieldType() {
check("int", e_a1.getFieldType());
check("int", e_a2.getFieldType());
-
+
// Test memoization - should return same instance
var type1 = e_a1.getFieldType();
var type2 = e_a1.getFieldType();
@@ -345,7 +345,7 @@ class FieldInfo_Test extends TestBase {
void a010_getFullName() throws Exception {
String fullName1 = g_field1.getNameFull();
String fullName2 = g_field2.getNameFull();
-
+
// Test line 449: getPackage() returns null (default package
class)
// A field can have a null package if its declaring class is in
the default package
// According to Java API, Class.getPackage() returns null for
classes in the default package
@@ -369,15 +369,15 @@ class FieldInfo_Test extends TestBase {
assertTrue(fullName1.endsWith("FieldInfo_Test$G.field1"));
assertTrue(fullName2.endsWith("FieldInfo_Test$G.field2"));
-
+
assertTrue(fullName1.startsWith("org.apache.juneau.commons.reflect."));
assertTrue(fullName2.startsWith("org.apache.juneau.commons.reflect."));
-
+
// Test memoization - should return same instance
String name1 = g_field1.getNameFull();
String name2 = g_field1.getNameFull();
assertSame(name1, name2);
-
+
// Test with inner class
String innerFullName = inner_field.getNameFull();
assertTrue(innerFullName.contains("FieldInfo_Test$InnerClass"));
@@ -457,19 +457,19 @@ class FieldInfo_Test extends TestBase {
assertFalse(c_isNotStatic.is(STATIC));
assertFalse(c_isTransient.is(NOT_TRANSIENT));
assertFalse(c_isNotTransient.is(TRANSIENT));
-
+
// Enum constant
assertTrue(testEnum_value1.is(ENUM_CONSTANT));
assertFalse(a1_f1.is(ENUM_CONSTANT));
assertTrue(a1_f1.is(NOT_ENUM_CONSTANT)); // Line 313: true
branch - field is NOT an enum constant
assertFalse(testEnum_value1.is(NOT_ENUM_CONSTANT)); // Line
313: false branch - field IS an enum constant
-
+
// Synthetic (lines 314-315)
assertFalse(a1_f1.is(SYNTHETIC));
assertTrue(a1_f1.is(NOT_SYNTHETIC));
assertFalse(b_a1.is(SYNTHETIC));
assertTrue(b_a1.is(NOT_SYNTHETIC));
-
+
// HAS_PARAMS doesn't apply to fields, should throw exception
assertThrowsWithMessage(RuntimeException.class, "Invalid flag
for element: HAS_PARAMS", () -> c_deprecated.is(HAS_PARAMS));
}
@@ -483,22 +483,22 @@ class FieldInfo_Test extends TestBase {
var privateBefore = d_isPrivate.isAccessible();
var protectedBefore = d_isProtected.isAccessible();
var defaultBefore = d_isDefault.isAccessible();
-
+
// Make them accessible
d_isPrivate.setAccessible();
d_isProtected.setAccessible();
d_isDefault.setAccessible();
-
+
// After setAccessible(), they should be accessible (if Java 9+)
var privateAfter = d_isPrivate.isAccessible();
var protectedAfter = d_isProtected.isAccessible();
var defaultAfter = d_isDefault.isAccessible();
-
+
// Verify the method doesn't throw and returns a boolean
assertTrue(privateAfter || !privateBefore, "After
setAccessible(), isAccessible() should return true (Java 9+) or false (Java
8)");
assertTrue(protectedAfter || !protectedBefore, "After
setAccessible(), isAccessible() should return true (Java 9+) or false (Java
8)");
assertTrue(defaultAfter || !defaultBefore, "After
setAccessible(), isAccessible() should return true (Java 9+) or false (Java
8)");
-
+
// Public fields might already be accessible
var publicAccessible = d_isPublic.isAccessible();
assertNotNull(publicAccessible);
@@ -601,7 +601,7 @@ class FieldInfo_Test extends TestBase {
@Test
void a026_of_withoutClass() {
check("f1", FieldInfo.of(a1_f1.inner()));
-
+
// Null should throw
assertThrows(IllegalArgumentException.class, () ->
FieldInfo.of((Field)null));
assertThrows(IllegalArgumentException.class, () ->
FieldInfo.of((ClassInfo)null, null));
@@ -613,13 +613,13 @@ class FieldInfo_Test extends TestBase {
@Test
void a027_set() {
var obj = new GetSetTest();
-
+
getSetTest_value.set(obj, "newValue");
assertEquals("newValue", obj.value);
-
+
getSetTest_number.set(obj, 100);
assertEquals(100, obj.number);
-
+
// Set to null
getSetTest_value.set(obj, null);
assertNull(obj.value);
@@ -642,12 +642,12 @@ class FieldInfo_Test extends TestBase {
@Test
void a029_setIfNull() {
var obj = new GetSetTest();
-
+
// Set when null
obj.value = null;
getSetTest_value.setIfNull(obj, "defaultValue");
assertEquals("defaultValue", obj.value);
-
+
// Don't set when not null
obj.value = "existing";
getSetTest_value.setIfNull(obj, "shouldNotSet");
@@ -775,43 +775,43 @@ class FieldInfo_Test extends TestBase {
Field f1 = EqualsTestClass.class.getField("field1");
FieldInfo fi1a = FieldInfo.of(f1);
FieldInfo fi1b = FieldInfo.of(f1);
-
+
Field f2 = EqualsTestClass.class.getField("field2");
FieldInfo fi2 = FieldInfo.of(f2);
// Same field should be equal
assertEquals(fi1a, fi1b);
assertEquals(fi1a.hashCode(), fi1b.hashCode());
-
+
// Different fields should not be equal
assertNotEquals(fi1a, fi2);
assertNotEquals(fi1a, null);
assertNotEquals(fi1a, "not a FieldInfo");
-
+
// Reflexive
assertEquals(fi1a, fi1a);
-
+
// Symmetric
assertEquals(fi1a, fi1b);
assertEquals(fi1b, fi1a);
-
+
// Transitive
FieldInfo fi1c = FieldInfo.of(f1);
assertEquals(fi1a, fi1b);
assertEquals(fi1b, fi1c);
assertEquals(fi1a, fi1c);
-
+
// HashMap usage - same field should map to same value
Map<FieldInfo, String> map = new HashMap<>();
map.put(fi1a, "value1");
assertEquals("value1", map.get(fi1b));
assertEquals("value1", map.get(fi1c));
-
+
// HashMap usage - different fields should map to different
values
map.put(fi2, "value2");
assertEquals("value2", map.get(fi2));
assertNotEquals("value2", map.get(fi1a));
-
+
// HashSet usage
Set<FieldInfo> set = new HashSet<>();
set.add(fi1a);