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 a4581a6268 Utility class modernization
a4581a6268 is described below
commit a4581a62682ed667118a3510947a0f1485a5a470
Author: James Bognar <[email protected]>
AuthorDate: Wed Nov 5 15:17:08 2025 -0500
Utility class modernization
---
.../juneau/common/reflect/AnnotationProvider2.java | 24 ++++-----
.../apache/juneau/common/reflect/ClassInfo.java | 63 ++++++++++++++++++++++
.../org/apache/juneau/common/utils/ClassUtils.java | 2 +
.../src/main/java/org/apache/juneau/ClassMeta.java | 9 +---
.../src/main/java/org/apache/juneau/Context.java | 1 +
.../java/org/apache/juneau/ClassMeta_Test.java | 15 ++----
6 files changed, 81 insertions(+), 33 deletions(-)
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider2.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider2.java
index 55c0ffab97..e425717e59 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider2.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider2.java
@@ -345,23 +345,19 @@ public class AnnotationProvider2 {
var ci = ClassInfo.of(forClass);
var list = new ArrayList<AnnotationInfo<Annotation>>();
- // On this class
- findDeclaredAnnotations(list, forClass);
-
- // On parent classes ordered child-to-parent
- var parents = ci.getParents();
- for (int i = 0; i < parents.size(); i++)
- findDeclaredAnnotations(list, parents.get(i).inner());
-
- // On interfaces ordered child-to-parent
- var interfaces = ci.getInterfaces();
- for (int i = 0; i < interfaces.size(); i++)
- findDeclaredAnnotations(list,
interfaces.get(i).inner());
+ // On all parent classes and interfaces (properly traversed to
avoid duplicates)
+ var parentsAndInterfaces = ci.getParentsAndInterfaces();
+ for (int i = 0; i < parentsAndInterfaces.size(); i++)
+ findDeclaredAnnotations(list,
parentsAndInterfaces.get(i).inner());
// On the package of this class
var pkg = ci.getPackage();
- if (nn(pkg))
- findDeclaredAnnotations(list, pkg.inner());
+ if (nn(pkg)) {
+ var pi = PackageInfo.of(pkg.inner());
+ for (var a : pkg.inner().getAnnotations())
+ for (var a2 : splitRepeated(a))
+ list.add(AnnotationInfo.of(pi, a2));
+ }
return u(list);
}
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 d064767dcc..6a91fc1c1b 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
@@ -222,8 +222,51 @@ public class ClassInfo extends ElementInfo implements
Annotatable {
private final Supplier<List<ClassInfo>> interfaces = memoize(() ->
getParents().stream().flatMap(x ->
x.getDeclaredInterfaces().stream()).flatMap(ci2 -> concat(Stream.of(ci2),
ci2.getInterfaces().stream())).distinct().toList());
// All parent classes and interfaces, classes first, then in
child-to-parent order.
+ // TODO - Determine if this field is still needed now that we have
parentsAndInterfaces which handles the hierarchy better.
private final Supplier<List<ClassInfo>> allParents = memoize(() ->
concat(getParents().stream(), getInterfaces().stream()).toList());
+ // All parent classes and interfaces with proper traversal of interface
hierarchy to avoid duplicates.
+ private final Supplier<List<ClassInfo>> parentsAndInterfaces =
memoize(this::findParentsAndInterfaces);
+
+ /**
+ * Finds all parent classes and interfaces with proper traversal of
interface hierarchy.
+ *
+ * @return A list of all parent classes and interfaces without
duplicates.
+ */
+ private List<ClassInfo> findParentsAndInterfaces() {
+ var set = new LinkedHashSet<ClassInfo>();
+
+ // Process all parent classes (includes this class)
+ var parents = getParents();
+ for (int i = 0; i < parents.size(); i++) {
+ var parent = parents.get(i);
+ set.add(parent);
+
+ // Process interfaces declared on this parent (and
their parent interfaces)
+ var declaredInterfaces = parent.getDeclaredInterfaces();
+ for (int j = 0; j < declaredInterfaces.size(); j++)
+ addInterfaceHierarchy(set,
declaredInterfaces.get(j));
+ }
+
+ return u(new ArrayList<>(set));
+ }
+
+ /**
+ * Helper method to recursively add an interface and its parent
interfaces to the set.
+ *
+ * @param set The set to add to.
+ * @param iface The interface to add.
+ */
+ private void addInterfaceHierarchy(LinkedHashSet<ClassInfo> set,
ClassInfo iface) {
+ if (!set.add(iface))
+ return;
+
+ // Process parent interfaces recursively
+ var parentInterfaces = iface.getParents();
+ for (int i = 0; i < parentInterfaces.size(); i++)
+ addInterfaceHierarchy(set, parentInterfaces.get(i));
+ }
+
// All record components if this is a record class (Java 14+).
private final Supplier<List<RecordComponent>> recordComponents =
memoize(() -> opt(c).filter(Class::isRecord).map(x ->
u(l(x.getRecordComponents()))).orElse(liste()));
@@ -915,6 +958,26 @@ public class ClassInfo extends ElementInfo implements
Annotatable {
*/
public List<ClassInfo> getInterfaces() { return interfaces.get(); }
+ /**
+ * Returns all parent classes and interfaces in proper traversal order.
+ *
+ * <p>
+ * This method returns a unique list of all parent classes (including
this class) and all interfaces
+ * (including interface hierarchies) with proper handling of
duplicates. The order is:
+ * <ol>
+ * <li>This class
+ * <li>Parent classes in child-to-parent order
+ * <li>For each class, interfaces declared on that class and their
parent interfaces
+ * </ol>
+ *
+ * <p>
+ * This is useful for annotation processing where you need to traverse
the complete type hierarchy
+ * without duplicates.
+ *
+ * @return An unmodifiable list of all parent classes and interfaces,
properly ordered without duplicates.
+ */
+ public List<ClassInfo> getParentsAndInterfaces() { return
parentsAndInterfaces.get(); }
+
/**
* Returns the first matching method on this class.
*
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/ClassUtils.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/ClassUtils.java
index eafb20be7d..65cfec54bd 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/ClassUtils.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/ClassUtils.java
@@ -649,6 +649,8 @@ public class ClassUtils {
* @return The simple name of the class or <jk>null</jk> if the value
was null.
*/
public static String simpleClassName(Object value) {
+ if (value instanceof ClassInfo)
+ return ((ClassInfo)value).getNameSimple();
return value == null ? null : value instanceof Class<?> ?
((Class<?>)value).getSimpleName() : value.getClass().getSimpleName();
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 8b0dec2190..4c4226d274 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -861,14 +861,9 @@ public class ClassMeta<T> implements Type {
* @return This object.
*/
public <A extends Annotation> ClassMeta<T> forEachAnnotation(Class<A>
type, Predicate<A> filter, Consumer<A> action) {
- A[] array = annotationArray(type);
- if (array == null) {
- if (beanContext == null)
- info.forEachAnnotation(BeanContext.DEFAULT,
type, filter, action);
- return this;
+ if (beanContext != null) {
+ beanContext.getAnnotationProvider().find(type,
info.inner()).map(x -> x.inner()).filter(x -> x != null).filter(x -> filter ==
null || filter.test(x)).forEach(x -> action.accept(x));
}
- for (var a : array)
- PredicateUtils.consumeIf(filter, action, a);
return this;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
index 7d8330f0e9..ce025328e4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
@@ -895,6 +895,7 @@ public abstract class Context implements AnnotationProvider
{
@Override /* Overridden from MetaProvider */
public <A extends Annotation> void forEachDeclaredAnnotation(Class<A>
type, Class<?> onClass, Predicate<A> filter, Consumer<A> action) {
+// getAnnotationProvider().find(type, onClass).map(x ->
x.inner()).filter(x -> filter.test(x)).forEach(x -> action.accept(x));
if (nn(type) && nn(onClass))
for (var a : declaredAnnotations(type, onClass))
consumeIf(filter, action, a);
diff --git a/juneau-utest/src/test/java/org/apache/juneau/ClassMeta_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/ClassMeta_Test.java
index dbef394671..c6af629f51 100755
--- a/juneau-utest/src/test/java/org/apache/juneau/ClassMeta_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/ClassMeta_Test.java
@@ -292,11 +292,12 @@ class ClassMeta_Test extends TestBase {
var l1 = list();
c3.forEachAnnotation(A.class, null, x -> l1.add(x.value()));
- assertList(l1, "2", "1", "3", "5", "6", "7");
+ System.err.println(l1);
+ assertList(l1, "7", "6", "3", "5", "1", "2");
var l2 = list();
c4.forEachAnnotation(A.class, null, x -> l2.add(x.value()));
- assertList(l2, "2", "1", "3", "5", "6", "7");
+ assertList(l2, "7", "6", "3", "5", "1", "2");
var l3 = list();
c5.forEachAnnotation(A.class, null, x -> l3.add(x.value()));
@@ -306,14 +307,4 @@ class ClassMeta_Test extends TestBase {
c3.forEachAnnotation(A.class, x -> x.value() == 5, x ->
l4.add(x.value()));
assertList(l4, "5");
}
-
- @Test void lastAnnotation() {
- var c3 = bc.getClassMeta(C3.class);
- var c4 = bc.getClassMeta(C4.class);
- var c5 = bc.getClassMeta(C5.class);
- assertEquals(7, c3.lastAnnotation(A.class, null).get().value());
- assertEquals(7, c4.lastAnnotation(A.class, null).get().value());
- assertEquals(3, c5.lastAnnotation(A.class, null).get().value());
- assertEquals(5, c3.lastAnnotation(A.class, x -> x.value() ==
5).get().value());
- }
}
\ No newline at end of file