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 d30953e63b New BeanCreator API
d30953e63b is described below
commit d30953e63b8cd806da5fe72107b2feeebfeb654b
Author: James Bognar <[email protected]>
AuthorDate: Wed Jan 21 12:10:13 2026 -0500
New BeanCreator API
---
.../apache/juneau/commons/reflect/ClassInfo.java | 59 ++++++++++++++++++++--
1 file changed, 55 insertions(+), 4 deletions(-)
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 b5e3b16904..67c39840d5 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
@@ -342,11 +342,11 @@ public class ClassInfo extends ElementInfo implements
Annotatable, Type, Compara
// Outer classes but no package
if (nn(ct)) {
if (ct.isLocalClass()) {
- // Local class: include
enclosing class simple name
-
sb.append(of(ct.getEnclosingClass()).getNameSimple()).append(separator).append(ct.getSimpleName());
+ // Local class: recursively
include all enclosing classes
+ appendShortNameWithOuters(sb,
of(ct.getEnclosingClass()),
separator).append(separator).append(ct.getSimpleName());
} else if (ct.isMemberClass()) {
- // Member class: include
declaring class simple name
-
sb.append(of(ct.getDeclaringClass()).getNameSimple()).append(separator).append(ct.getSimpleName());
+ // Member class: recursively
include all declaring classes
+ appendShortNameWithOuters(sb,
of(ct.getDeclaringClass()),
separator).append(separator).append(ct.getSimpleName());
} else {
// Regular class: just simple
name
sb.append(ct.getSimpleName());
@@ -383,6 +383,31 @@ public class ClassInfo extends ElementInfo implements
Annotatable, Type, Compara
return sb;
}
+ /**
+ * Helper method to recursively append short name with all outer
classes for SHORT format.
+ * This ensures multiply-nested classes include all outer class names.
+ *
+ * @param sb The StringBuilder to append to.
+ * @param classInfo The ClassInfo to append.
+ * @param separator The separator character between outer and inner
classes.
+ */
+ private StringBuilder appendShortNameWithOuters(StringBuilder sb,
ClassInfo classInfo, char separator) {
+ var ct = classInfo.inner();
+ if (ct == null) {
+ sb.append(classInfo.getNameSimple());
+ return sb;
+ }
+
+ if (ct.isLocalClass()) {
+ appendShortNameWithOuters(sb,
of(ct.getEnclosingClass()),
separator).append(separator).append(ct.getSimpleName());
+ } else if (ct.isMemberClass()) {
+ appendShortNameWithOuters(sb,
of(ct.getDeclaringClass()),
separator).append(separator).append(ct.getSimpleName());
+ } else {
+ sb.append(ct.getSimpleName());
+ }
+ return sb;
+ }
+
/**
* Returns a {@link ClassInfo} for an array type whose component type
is this class.
*
@@ -2789,6 +2814,18 @@ public class ClassInfo extends ElementInfo implements
Annotatable, Type, Compara
* <li>Supports the same parameter types as parameter resolution:
single beans, {@code Optional}, arrays, {@code List}, {@code Set}, {@code Map}
* </ul>
*
+ * <h5 class='section'>PostConstruct Methods:</h5>
+ * <ul class='spaced-list'>
+ * <li>Must be annotated with {@code @PostConstruct} (matched by
simple class name)
+ * <li>Must return {@code void}
+ * <li>Must have no parameters
+ * <li>Must not be abstract
+ * <li>Must not declare type parameters
+ * <li>Called after all field and method injection is complete
+ * <li>Called in parent-to-child order (parent methods execute
before child methods)
+ * <li>Multiple methods can be annotated, and all will be called
in order
+ * </ul>
+ *
* <h5 class='section'>Example:</h5>
* <p class='bjava'>
* <jc>// Class with injectable fields and methods</jc>
@@ -2803,6 +2840,11 @@ public class ClassInfo extends ElementInfo implements
Annotatable, Type, Compara
* <jk>public</jk> <jk>void</jk> init(MyConfig
<jv>config</jv>) {
* <jc>// Initialization logic</jc>
* }
+ *
+ * <ja>@PostConstruct</ja>
+ * <jk>public</jk> <jk>void</jk> postConstruct() {
+ * <jc>// Called after all injection is
complete</jc>
+ * }
* }
*
* <jc>// Inject beans</jc>
@@ -2825,6 +2867,15 @@ public class ClassInfo extends ElementInfo implements
Annotatable, Type, Compara
// Inject into methods
getAllMethods().stream()
.filter(x -> x.isNotAbstract() &&
eq(x.getTypeParameters().length, 0) &&
x.getAnnotations().stream().map(AnnotationInfo::getNameSimple).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));
+
+ // Call @PostConstruct methods after all injection is complete
+ // Use getAllMethodsTopDown() to ensure parent methods are
called before child methods
+ getAllMethodsTopDown().stream()
+ .filter(x -> x.isNotAbstract() &&
eq(x.getTypeParameters().length, 0))
+ .filter(x -> x.getReturnType().is(void.class) &&
eq(x.getParameterCount(), 0))
+ .filter(x ->
x.getAnnotations().stream().map(AnnotationInfo::getNameSimple).anyMatch(n ->
eq(n, "PostConstruct")))
.forEach(x -> x.inject(beanStore, bean));
return bean;