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

Reply via email to