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 edbe0d2724 org.apache.juneau.common.reflect API improvements
edbe0d2724 is described below
commit edbe0d2724fe627ce0d56704fadb747978c622ca
Author: James Bognar <[email protected]>
AuthorDate: Mon Nov 17 12:50:12 2025 -0500
org.apache.juneau.common.reflect API improvements
---
.../apache/juneau/common/reflect/ClassInfo.java | 87 ++++++++++++++++++++--
.../java/org/apache/juneau/rest/RestContext.java | 6 +-
2 files changed, 82 insertions(+), 11 deletions(-)
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ClassInfo.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ClassInfo.java
index 9aa9217cea..4f38bf3f13 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ClassInfo.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ClassInfo.java
@@ -198,7 +198,7 @@ public class ClassInfo extends ElementInfo implements
Annotatable {
private final Supplier<List<MethodInfo>> publicMethods; // All public
methods on this class and inherited, excluding Object methods.
private final Supplier<List<MethodInfo>> declaredMethods; // All
methods declared directly on this class (public, protected, package, private).
private final Supplier<List<MethodInfo>> allMethods; // All methods
from this class and all parents, in child-to-parent order.
- private final Supplier<List<MethodInfo>> allMethodsParentFirst; // All
methods from this class and all parents, in parent-to-child order.
+ private final Supplier<List<MethodInfo>> allMethodsTopDown; // All
methods from this class and all parents, in parent-to-child order.
private final Supplier<List<FieldInfo>> publicFields; // All public
fields from this class and parents, deduplicated by name (child wins).
private final Supplier<List<FieldInfo>> declaredFields; // All fields
declared directly on this class (public, protected, package, private).
private final Supplier<List<FieldInfo>> allFields; // All fields from
this class and all parents, in parent-to-child order.
@@ -242,7 +242,7 @@ public class ClassInfo extends ElementInfo implements
Annotatable {
this.publicMethods = memoize(() -> opt(inner).map(x ->
stream(x.getMethods()).filter(m -> ne(m.getDeclaringClass(),
Object.class)).map(this::getMethod).sorted().toList()).orElse(liste()));
this.declaredMethods = memoize(() -> opt(inner).map(x ->
stream(x.getDeclaredMethods()).filter(m -> ne("$jacocoInit",
m.getName())).map(this::getMethod).sorted().toList()).orElse(liste()));
this.allMethods = memoize(() ->
allParents.get().stream().flatMap(c2 ->
c2.getDeclaredMethods().stream()).toList());
- this.allMethodsParentFirst = memoize(() ->
rstream(getAllParents()).flatMap(c2 ->
c2.getDeclaredMethods().stream()).toList());
+ this.allMethodsTopDown = memoize(() ->
rstream(getAllParents()).flatMap(c2 ->
c2.getDeclaredMethods().stream()).toList());
this.publicFields = memoize(() ->
parents.get().stream().flatMap(c2 -> c2.getDeclaredFields().stream()).filter(f
-> f.isPublic() && ne("$jacocoData",
f.getName())).collect(toMap(FieldInfo::getName, x -> x, (a, b) -> a,
LinkedHashMap::new)).values().stream().sorted().collect(toList()));
this.declaredFields = memoize(() -> opt(inner).map(x ->
stream(x.getDeclaredFields()).filter(f -> ne("$jacocoData",
f.getName())).map(this::getField).sorted().toList()).orElse(liste()));
this.allFields = memoize(() ->
rstream(allParents.get()).flatMap(c2 ->
c2.getDeclaredFields().stream()).toList());
@@ -305,14 +305,59 @@ public class ClassInfo extends ElementInfo implements
Annotatable {
public List<FieldInfo> getAllFields() { return allFields.get(); }
/**
- * Returns all declared methods on this class and all parent classes.
+ * Returns all declared methods on this class and all parent classes in
<b>parent-to-child order</b>.
+ *
+ * <p>
+ * This method returns methods of <b>all visibility levels</b> (public,
protected, package-private, and private).
+ *
+ * <p>
+ * Methods are returned in <b>parent-to-child order</b> - methods from
the most distant ancestor appear first,
+ * followed by methods from each subsequent child class, ending with
methods from the current class. Within
+ * each class, methods are sorted alphabetically.
+ *
+ * <p>
+ * This ordering is useful for initialization hooks and lifecycle
methods where parent methods should execute
+ * before child methods (e.g., <c>@RestInit</c>, <c>@PostConstruct</c>,
etc.).
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * <jc>// Given class hierarchy:</jc>
+ * <jk>class</jk> Parent {
+ * <jk>void</jk> method1() {}
+ * <jk>void</jk> method2() {}
+ * }
+ * <jk>class</jk> Child <jk>extends</jk> Parent {
+ * <jk>void</jk> method3() {}
+ * <jk>void</jk> method4() {}
+ * }
+ *
+ * <jc>// getAllMethodsParentFirst() returns in parent-to-child
order:</jc>
+ * ClassInfo <jv>ci</jv> =
ClassInfo.<jsm>of</jsm>(Child.<jk>class</jk>);
+ * List<MethodInfo> <jv>methods</jv> =
<jv>ci</jv>.getAllMethodsParentFirst();
+ * <jc>// Returns: [method1, method2, method3, method4]</jc>
+ * <jc>// ^Parent methods^ ^Child methods^</jc>
+ * </p>
+ *
+ * <h5 class='section'>Comparison with Similar Methods:</h5>
+ * <ul class='spaced-list'>
+ * <li>{@link #getDeclaredMethods()} - Returns methods declared on
this class only (all visibility levels)
+ * <li>{@link #getAllMethods()} - Returns all methods in
<b>child-to-parent order</b>
+ * <li>{@link #getAllMethodsTopDown()} - Returns all methods in
<b>parent-to-child order</b> ← This method
+ * <li>{@link #getPublicMethods()} - Returns public methods only
on this class and parents
+ * </ul>
+ *
+ * <h5 class='section'>Notes:</h5>
+ * <ul class='spaced-list'>
+ * <li>Methods from {@link Object} class are excluded from the
results.
+ * <li>Use {@link #getAllMethods()} if you need child methods to
appear before parent methods.
+ * </ul>
*
* @return
- * All declared methods on this class and all parent classes.
+ * All declared methods on this class and all parent classes (all
visibility levels).
* <br>Results are ordered parent-to-child, and then
alphabetically per class.
* <br>List is unmodifiable.
*/
- public List<MethodInfo> getAllMethodsParentFirst() { return
allMethodsParentFirst.get(); }
+ public List<MethodInfo> getAllMethodsTopDown() { return
allMethodsTopDown.get(); }
/**
* Returns a list including this class and all parent classes and
interfaces.
@@ -880,15 +925,40 @@ public class ClassInfo extends ElementInfo implements
Annotatable {
}
/**
- * Returns all declared methods on this class and all parent classes.
+ * Returns all declared methods on this class and all parent classes in
<b>child-to-parent order</b>.
*
* <p>
* This method returns methods of <b>all visibility levels</b> (public,
protected, package-private, and private).
*
+ * <p>
+ * Methods are returned in <b>child-to-parent order</b> - methods from
the current class appear first,
+ * followed by methods from the immediate parent, then grandparent,
etc. Within each class, methods
+ * are sorted alphabetically.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * <jc>// Given class hierarchy:</jc>
+ * <jk>class</jk> Parent {
+ * <jk>void</jk> method1() {}
+ * <jk>void</jk> method2() {}
+ * }
+ * <jk>class</jk> Child <jk>extends</jk> Parent {
+ * <jk>void</jk> method3() {}
+ * <jk>void</jk> method4() {}
+ * }
+ *
+ * <jc>// getAllMethods() returns in child-to-parent order:</jc>
+ * ClassInfo <jv>ci</jv> =
ClassInfo.<jsm>of</jsm>(Child.<jk>class</jk>);
+ * List<MethodInfo> <jv>methods</jv> =
<jv>ci</jv>.getAllMethods();
+ * <jc>// Returns: [method3, method4, method1, method2]</jc>
+ * <jc>// ^Child methods^ ^Parent methods^</jc>
+ * </p>
+ *
* <h5 class='section'>Comparison with Similar Methods:</h5>
* <ul class='spaced-list'>
- * <li>{@link #getDeclaredMethods()} - Returns all declared
methods on this class only (all visibility levels)
- * <li>{@link #getAllMethods()} - Returns all declared methods on
this class and parents (all visibility levels) ← This method
+ * <li>{@link #getDeclaredMethods()} - Returns methods declared on
this class only (all visibility levels)
+ * <li>{@link #getAllMethods()} - Returns all methods in
<b>child-to-parent order</b> ← This method
+ * <li>{@link #getAllMethodsTopDown()} - Returns all methods in
<b>parent-to-child order</b>
* <li>{@link #getPublicMethods()} - Returns public methods only
on this class and parents
* </ul>
*
@@ -896,6 +966,7 @@ public class ClassInfo extends ElementInfo implements
Annotatable {
* <ul class='spaced-list'>
* <li>Unlike Java's {@link Class#getMethods()}, this returns
methods of all visibility levels, not just public ones.
* <li>Methods from {@link Object} class are excluded from the
results.
+ * <li>Use {@link #getAllMethodsTopDown()} if you need parent
methods to appear before child methods.
* </ul>
*
* @return
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index a9d958ea64..036037cdc2 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -203,7 +203,7 @@ public class RestContext extends Context {
var r = resource.get();
// @formatter:off
- ClassInfo.ofProxy(r).getAllMethodsParentFirst().stream()
+ ClassInfo.ofProxy(r).getAllMethodsTopDown().stream()
.filter(y -> y.hasAnnotation(annotation))
.forEach(y ->
rstream(y.getAllAnnotations()).map(ai ->
ai.cast(annotation)).filter(Objects::nonNull).map(AnnotationInfo::inner)
.filter(z -> predicate == null ||
predicate.test(z))
@@ -3781,7 +3781,7 @@ public class RestContext extends Context {
var map = CollectionUtils.<String,MethodInfo>map();
// @formatter:off
- ClassInfo.ofProxy(r).getAllMethodsParentFirst().stream()
+ ClassInfo.ofProxy(r).getAllMethodsTopDown().stream()
.filter(y -> y.hasAnnotation(RestInit.class) &&
! y.hasParameter(RestOpContext.Builder.class))
.forEach(y -> {
var sig = y.getSignature();
@@ -4571,7 +4571,7 @@ public class RestContext extends Context {
var initMap = CollectionUtils.<String,MethodInfo>map();
// @formatter:off
-
ClassInfo.ofProxy(resource.get()).getAllMethodsParentFirst().stream()
+
ClassInfo.ofProxy(resource.get()).getAllMethodsTopDown().stream()
.filter(y -> y.hasAnnotation(RestInit.class) &&
y.hasParameter(RestOpContext.Builder.class))
.forEach(y -> {
String sig = y.getSignature();