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 ef8410d521 New BeanCreator API
ef8410d521 is described below
commit ef8410d521fef0564d84fa6ad2d18886568e0cb9
Author: James Bognar <[email protected]>
AuthorDate: Wed Jan 21 11:05:05 2026 -0500
New BeanCreator API
---
.../juneau/commons/reflect/ParameterInfo.java | 77 +++++++++++++++++-
.../commons/reflect/ExecutableInfo_Test.java | 17 +++-
.../juneau/commons/reflect/ParameterInfo_Test.java | 90 +++++++++++++++++++++-
3 files changed, 177 insertions(+), 7 deletions(-)
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 f24312c370..e8af8326e8 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
@@ -16,6 +16,8 @@
*/
package org.apache.juneau.commons.reflect;
+import static org.apache.juneau.commons.reflect.ClassArrayFormat.*;
+import static org.apache.juneau.commons.reflect.ClassNameFormat.*;
import static org.apache.juneau.commons.utils.AssertionUtils.*;
import static org.apache.juneau.commons.utils.CollectionUtils.*;
import static org.apache.juneau.commons.utils.ThrowableUtils.*;
@@ -155,6 +157,8 @@ public class ParameterInfo extends ElementInfo implements
Annotatable {
private final ResettableSupplier<String> resolvedQualifier =
memr(this::findQualifierInternal); // Resolved qualifier from @Named or
@Qualifier annotation.
+ private final Supplier<String> toString; // String representation with
modifiers, type, name, and varargs flag.
+
/**
* Constructor.
*
@@ -177,6 +181,7 @@ public class ParameterInfo extends ElementInfo implements
Annotatable {
this.type = type;
this.annotations = mem(() ->
stream(inner.getAnnotations()).flatMap(a ->
AnnotationUtils.streamRepeated(a)).map(a -> ai(this, a)).toList());
this.matchingParameters = mem(this::findMatchingParameters);
+ this.toString = mem(this::findToString);
}
/**
@@ -612,9 +617,79 @@ public class ParameterInfo extends ElementInfo implements
Annotatable {
*/
public boolean isVarArgs() { return inner.isVarArgs(); }
+ /**
+ * Returns a detailed string representation of this parameter.
+ *
+ * <p>
+ * The returned string includes:
+ * <ul>
+ * <li>Modifiers (final)
+ * <li>Parameter type with generics (e.g., "List<String>")
+ * <li>Parameter name (if available)
+ * <li>Varargs indicator (if applicable)
+ * </ul>
+ *
+ * <h5 class='section'>Examples:</h5>
+ * <p class='bjava'>
+ * <jc>// Simple parameter</jc>
+ * ParameterInfo <jv>pi</jv> = ...;
+ * <jv>pi</jv>.toString();
+ * <jc>// Returns: "java.lang.String name"</jc>
+ *
+ * <jc>// Final parameter</jc>
+ * <jc>// Returns: "final java.lang.String name"</jc>
+ *
+ * <jc>// Generic parameter</jc>
+ * <jc>// Returns: "java.util.List<java.lang.String>
items"</jc>
+ *
+ * <jc>// Varargs parameter</jc>
+ * <jc>// Returns: "java.lang.String... values"</jc>
+ *
+ * <jc>// Parameter without name (fallback)</jc>
+ * <jc>// Returns: "int arg0"</jc>
+ * </p>
+ *
+ * @return A detailed string representation including modifiers, type,
name, and varargs flag.
+ */
@Override
public String toString() {
- return (executable.getNameSimple()) + "[" + index + "]";
+ return toString.get();
+ }
+
+ private String findToString() {
+ var sb = new StringBuilder(128);
+
+ // Modifiers (final is common for parameters)
+ var mods = Modifier.toString(getModifiers());
+ if (nn(mods) && ! mods.isEmpty()) {
+ sb.append(mods).append(" ");
+ }
+
+ // 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
+ var typeInfo = ClassInfo.of(paramType);
+ var componentType = typeInfo.getComponentType();
+ // Display the component type without array brackets,
then add "..."
+ componentType.appendNameFormatted(sb, FULL, true, '$',
BRACKETS);
+ sb.append("...");
+ } else {
+ ClassInfo.of(paramType).appendNameFormatted(sb, FULL,
true, '$', BRACKETS);
+ }
+
+ // Parameter name (if available)
+ var name = getResolvedName();
+ if (nn(name)) {
+ sb.append(" ").append(name);
+ } else {
+ // Fallback to index-based name if no name available
+ sb.append(" arg").append(index);
+ }
+
+ return sb.toString();
}
private List<ParameterInfo> findMatchingParameters() {
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ExecutableInfo_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ExecutableInfo_Test.java
index f55ab88433..f153989501 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ExecutableInfo_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ExecutableInfo_Test.java
@@ -343,8 +343,13 @@ class ExecutableInfo_Test extends TestBase {
//====================================================================================================
@Test
void a011_getParameter() {
- check("B[0]", b_c2.getParameter(0));
- check("m[0]", b_m2.getParameter(0));
+ // b_c2 is B(String s) constructor, parameter name may or may
not be available in bytecode
+ var param1 = b_c2.getParameter(0).toString();
+ assertTrue(param1.equals("java.lang.String s") ||
param1.equals("java.lang.String arg0"), "Expected 'java.lang.String s' or
'java.lang.String arg0', got: " + param1);
+
+ // b_m2 is m(String s) method, parameter name may or may not be
available in bytecode
+ var param2 = b_m2.getParameter(0).toString();
+ assertTrue(param2.equals("java.lang.String s") ||
param2.equals("java.lang.String arg0"), "Expected 'java.lang.String s' or
'java.lang.String arg0', got: " + param2);
// Index out of bounds
assertThrowsWithMessage(IndexOutOfBoundsException.class,
"Invalid index '0'. No parameters.", ()->b_c1.getParameter(0));
@@ -369,9 +374,13 @@ class ExecutableInfo_Test extends TestBase {
@Test
void a013_getParameters() {
check("", b_c1.getParameters());
- check("B[0]", b_c2.getParameters());
+ // b_c2 is B(String s) constructor, parameter name may or may
not be available in bytecode
+ var params1 =
b_c2.getParameters().stream().map(ParameterInfo::toString).collect(Collectors.joining(","));
+ assertTrue(params1.equals("java.lang.String s") ||
params1.equals("java.lang.String arg0"), "Expected 'java.lang.String s' or
'java.lang.String arg0', got: " + params1);
check("", b_m1.getParameters());
- check("m[0]", b_m2.getParameters());
+ // b_m2 is m(String s) method, parameter name may or may not be
available in bytecode
+ var params2 =
b_m2.getParameters().stream().map(ParameterInfo::toString).collect(Collectors.joining(","));
+ assertTrue(params2.equals("java.lang.String s") ||
params2.equals("java.lang.String arg0"), "Expected 'java.lang.String s' or
'java.lang.String arg0', got: " + params2);
// Test caching - should return same result
check("", b_c1.getParameters());
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java
index 6f42a82965..8071272d65 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java
@@ -267,7 +267,22 @@ class ParameterInfo_Test extends TestBase {
public PC4(String foo, int bar) {} // NOSONAR
}
public static class PC5 extends PC4 {
- public PC5(String foo) { super(foo, 0); } // NOSONAR
+ public PC5(String foo) { super(foo, 0); }
+ }
+
+ // Test class for toString() comprehensive tests
+ public static class ToStringTestClass {
+ public void basicMethod(int a, String b) {} // NOSONAR
+ public void namedMethod(@org.apache.juneau.annotation.Name("x")
int x, @org.apache.juneau.annotation.Name("y") String y) {} // NOSONAR
+ public void finalMethod(final int value) {} // NOSONAR
+ public void
genericMethod(@org.apache.juneau.annotation.Name("list") java.util.List<String>
list, @org.apache.juneau.annotation.Name("map") java.util.Map<String, Integer>
map) {} // NOSONAR
+ public void
varargsMethod(@org.apache.juneau.annotation.Name("values") String... values) {}
// NOSONAR
+ public void finalVarargsMethod(final
@org.apache.juneau.annotation.Name("args") String... args) {} // NOSONAR
+ public void
arrayMethod(@org.apache.juneau.annotation.Name("numbers") int[] numbers,
@org.apache.juneau.annotation.Name("matrix") String[][] matrix) {} // NOSONAR
+ public void
genericArrayMethod(@org.apache.juneau.annotation.Name("lists")
java.util.List<String>[] lists) {} // NOSONAR
+ public void
primitiveMethod(@org.apache.juneau.annotation.Name("flag") boolean flag,
@org.apache.juneau.annotation.Name("value") double value,
@org.apache.juneau.annotation.Name("count") long count) {} // NOSONAR
+ public
ToStringTestClass(@org.apache.juneau.annotation.Name("id") int id,
@org.apache.juneau.annotation.Name("name") String name) {} // NOSONAR
+ public void unnamedMethod(int param1, String param2) {} //
NOSONAR - no @Name annotations, will fallback to arg0, arg1
}
public static class PC6 {
@@ -864,7 +879,78 @@ class ParameterInfo_Test extends TestBase {
//====================================================================================================
@Test
void a029_toString() {
- assertEquals("a1[1]", e_a1_b.toString());
+ // e_a1_b is the second parameter of method a1(int a,
@Name("b") int b)
+ // It has @Name("b") annotation, so resolved name is "b"
+ assertEquals("int b", e_a1_b.toString());
+ }
+
+ @Test
+ void a030_toString_comprehensive() {
+ var ci = ClassInfo.of(ToStringTestClass.class);
+
+ // Basic parameters (names may or may not be available in
bytecode)
+ var method1 = ci.getPublicMethod(x ->
x.hasName("basicMethod")).get();
+ var param1_0 = method1.getParameter(0).toString();
+ assertTrue(param1_0.equals("int a") || param1_0.equals("int
arg0"), "Expected 'int a' or 'int arg0', got: " + param1_0);
+ var param1_1 = method1.getParameter(1).toString();
+ assertTrue(param1_1.equals("java.lang.String b") ||
param1_1.equals("java.lang.String arg1"), "Expected 'java.lang.String b' or
'java.lang.String arg1', got: " + param1_1);
+
+ // Parameters with @Name annotation (always have names)
+ var method2 = ci.getPublicMethod(x ->
x.hasName("namedMethod")).get();
+ assertEquals("int x", method2.getParameter(0).toString());
+ assertEquals("java.lang.String y",
method2.getParameter(1).toString());
+
+ // Final parameters (final modifier may or may not appear
depending on JVM/environment)
+ // Accept both with and without final modifier
+ var method3 = ci.getPublicMethod(x ->
x.hasName("finalMethod")).get();
+ var param3_0 = method3.getParameter(0).toString();
+ assertTrue(
+ param3_0.equals("int value") || param3_0.equals("int
arg0") ||
+ param3_0.equals("final int value") ||
param3_0.equals("final int arg0"),
+ "Expected 'int value', 'int arg0', 'final int value',
or 'final int arg0', got: " + param3_0);
+
+ // Generic parameters
+ var method4 = ci.getPublicMethod(x ->
x.hasName("genericMethod")).get();
+ assertEquals("java.util.List<java.lang.String> list",
method4.getParameter(0).toString());
+ assertEquals("java.util.Map<java.lang.String,java.lang.Integer>
map", method4.getParameter(1).toString());
+
+ // Varargs parameter
+ var method5 = ci.getPublicMethod(x ->
x.hasName("varargsMethod")).get();
+ assertEquals("java.lang.String... values",
method5.getParameter(0).toString());
+
+ // Final varargs parameter (final modifier may or may not
appear depending on JVM/environment)
+ var method6 = ci.getPublicMethod(x ->
x.hasName("finalVarargsMethod")).get();
+ var param6_0 = method6.getParameter(0).toString();
+ assertTrue(
+ param6_0.equals("java.lang.String... args") ||
param6_0.equals("final java.lang.String... args"),
+ "Expected 'java.lang.String... args' or 'final
java.lang.String... args', got: " + param6_0);
+
+ // Array parameters
+ var method7 = ci.getPublicMethod(x ->
x.hasName("arrayMethod")).get();
+ assertEquals("int[] numbers",
method7.getParameter(0).toString());
+ assertEquals("java.lang.String[][] matrix",
method7.getParameter(1).toString());
+
+ // Generic array parameters
+ var method8 = ci.getPublicMethod(x ->
x.hasName("genericArrayMethod")).get();
+ assertEquals("java.util.List<java.lang.String>[] lists",
method8.getParameter(0).toString());
+
+ // Primitive types
+ var method9 = ci.getPublicMethod(x ->
x.hasName("primitiveMethod")).get();
+ assertEquals("boolean flag",
method9.getParameter(0).toString());
+ assertEquals("double value",
method9.getParameter(1).toString());
+ assertEquals("long count", method9.getParameter(2).toString());
+
+ // Constructor parameters (with @Name annotations, always have
names)
+ var ctor1 = ci.getPublicConstructor(x -> x.getParameterCount()
== 2).get();
+ assertEquals("int id", ctor1.getParameter(0).toString());
+ assertEquals("java.lang.String name",
ctor1.getParameter(1).toString());
+
+ // Parameters without @Name annotations (names may or may not
be available in bytecode)
+ var method10 = ci.getPublicMethod(x ->
x.hasName("unnamedMethod")).get();
+ var param10_0 = method10.getParameter(0).toString();
+ assertTrue(param10_0.equals("int param1") ||
param10_0.equals("int arg0"), "Expected 'int param1' or 'int arg0', got: " +
param10_0);
+ var param10_1 = method10.getParameter(1).toString();
+ assertTrue(param10_1.equals("java.lang.String param2") ||
param10_1.equals("java.lang.String arg1"), "Expected 'java.lang.String param2'
or 'java.lang.String arg1', got: " + param10_1);
}
//====================================================================================================