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 aaf24eb  Collections usage optimizations.
aaf24eb is described below

commit aaf24ebf755b90708c1af114ed12f48c54026002
Author: JamesBognar <[email protected]>
AuthorDate: Sun Mar 13 12:51:29 2022 -0400

    Collections usage optimizations.
---
 .../src/main/java/org/apache/juneau/ClassMeta.java |  62 +++++-
 .../org/apache/juneau/internal/ArrayUtils.java     |  15 ++
 .../java/org/apache/juneau/reflect/ClassInfo.java  | 140 +++++++++++-
 .../test/java/org/apache/juneau/ClassMetaTest.java | 244 ++++++++++++---------
 .../org/apache/juneau/reflect/ClassInfoTest.java   |  38 +++-
 5 files changed, 383 insertions(+), 116 deletions(-)

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 81c02d8..7b49599 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
@@ -2091,14 +2091,62 @@ public final class ClassMeta<T> implements Type {
         * @param action An action to perform on the entry.
         * @return This object.
         */
-       @SuppressWarnings("unchecked")
        public <A extends Annotation> ClassMeta<T> forEachAnnotation(Class<A> 
type, Predicate<A> filter, Consumer<A> action) {
-               A[] array = (A[])annotationArrayMap.get(type);
+               A[] array = annotationArray(type);
                if (array == null) {
-                       if (beanContext == null) {
+                       if (beanContext == null)
                                info.forEachAnnotation(BeanContext.DEFAULT, 
type, filter, action);
-                               return this;
-                       }
+                       return this;
+               }
+               for (A a : array)
+                       consume(filter, action, a);
+               return this;
+       }
+
+       /**
+        * Returns the first matching annotation on this class or parent 
classes/interfaces in parent-to-child order.
+        *
+        * @param type The annotation to search for.
+        * @param filter A predicate to apply to the entries to determine if 
annotation should be used.  Can be <jk>null</jk>.
+        * @return This object.
+        */
+       public <A extends Annotation> Optional<A> firstAnnotation(Class<A> 
type, Predicate<A> filter) {
+               A[] array = annotationArray(type);
+               if (array == null) {
+                       if (beanContext == null)
+                               return 
Optional.ofNullable(info.firstAnnotation(BeanContext.DEFAULT, type, filter));
+                       return Optional.empty();
+               }
+               for (A a : array)
+                       if (passes(filter, a))
+                               return Optional.of(a);
+               return Optional.empty();
+       }
+
+       /**
+        * Returns the last matching annotation on this class or parent 
classes/interfaces in parent-to-child order.
+        *
+        * @param type The annotation to search for.
+        * @param filter A predicate to apply to the entries to determine if 
annotation should be used.  Can be <jk>null</jk>.
+        * @return This object.
+        */
+       public <A extends Annotation> Optional<A> lastAnnotation(Class<A> type, 
Predicate<A> filter) {
+               A[] array = annotationArray(type);
+               if (array == null) {
+                       if (beanContext == null)
+                               return 
Optional.ofNullable(info.lastAnnotation(BeanContext.DEFAULT, type, filter));
+                       return Optional.empty();
+               }
+               for (int i = array.length-1; i >= 0; i--)
+                       if (passes(filter, array[i]))
+                               return Optional.of(array[i]);
+               return Optional.empty();
+       }
+
+       @SuppressWarnings("unchecked")
+       private <A extends Annotation> A[] annotationArray(Class<A> type) {
+               A[] array = (A[])annotationArrayMap.get(type);
+               if (array == null && beanContext != null) {
                        List<A> l = list();
                        info.forEachAnnotation(beanContext, type, x-> true, x 
-> l.add(x));
                        array = (A[])Array.newInstance(type, l.size());
@@ -2106,9 +2154,7 @@ public final class ClassMeta<T> implements Type {
                                Array.set(array, i, l.get(i));
                        annotationArrayMap.put(type, array);
                }
-               for (A a : array)
-                       consume(filter, action, a);
-               return this;
+               return array;
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ArrayUtils.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ArrayUtils.java
index 5ea415d..eb1df27 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ArrayUtils.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ArrayUtils.java
@@ -348,4 +348,19 @@ public final class ArrayUtils {
        public static final boolean isEmptyArray(Object[] array1, Object[] 
array2) {
                return isEmptyArray(array1) && isEmptyArray(array2);
        }
+
+       /**
+        * Reverses the entries in an array.
+        * 
+        * @param array The array to reverse.
+        * @return The same array.
+        */
+       public static final <T> T[] reverse(T[] array) {
+               for (int i = 0; i < array.length / 2; i++) {
+                       T temp = array[i];
+                       array[i] = array[array.length - i - 1];
+                       array[array.length - i - 1] = temp;
+               }
+               return array;
+       }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
index c2c9cfb..6e72595 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
@@ -923,7 +923,7 @@ public final class ClassInfo {
         * @return The matching annotations.
         */
        public <A extends Annotation> List<A> getAnnotations(Class<A> type) {
-               return getAnnotations(AnnotationProvider.DEFAULT, type);
+               return getAnnotations(null, type);
        }
 
        /**
@@ -951,7 +951,7 @@ public final class ClassInfo {
         * @return This object.
         */
        public <A extends Annotation> ClassInfo forEachAnnotation(Class<A> 
type, Predicate<A> filter, Consumer<A> action) {
-               return forEachAnnotation(AnnotationProvider.DEFAULT, type, 
filter, action);
+               return forEachAnnotation(null, type, filter, action);
        }
 
        /**
@@ -961,8 +961,8 @@ public final class ClassInfo {
         * Annotations are appended in the following orders:
         * <ol>
         *      <li>On the package of this class.
-        *      <li>On interfaces ordered child-to-parent.
-        *      <li>On parent classes ordered child-to-parent.
+        *      <li>On interfaces ordered parent-to-child.
+        *      <li>On parent classes ordered parent-to-child.
         *      <li>On this class.
         * </ol>
         *
@@ -973,8 +973,6 @@ public final class ClassInfo {
         * @return This object.
         */
        public <A extends Annotation> ClassInfo 
forEachAnnotation(AnnotationProvider annotationProvider, Class<A> type, 
Predicate<A> filter, Consumer<A> action) {
-               if (filter == null)
-                       filter = x->true;
                if (annotationProvider == null)
                        annotationProvider = AnnotationProvider.DEFAULT;
                A t2 = getPackageAnnotation(type);
@@ -990,6 +988,124 @@ public final class ClassInfo {
        }
 
        /**
+        * Returns the first matching annotation on this class and 
superclasses/interfaces.
+        *
+        * <p>
+        * Annotations are searched in the following orders:
+        * <ol>
+        *      <li>On the package of this class.
+        *      <li>On interfaces ordered parent-to-child.
+        *      <li>On parent classes ordered parent-to-child.
+        *      <li>On this class.
+        * </ol>
+        *
+        * @param type The annotation to look for.
+        * @param filter A predicate to apply to the entries to determine if 
annotation should be returned.  Can be <jk>null</jk>.
+        * @return This object.
+        */
+       public <A extends Annotation> A firstAnnotation(Class<A> type, 
Predicate<A> filter) {
+               return firstAnnotation(null, type, filter);
+       }
+
+       /**
+        * Returns the first matching annotation on this class and 
superclasses/interfaces.
+        *
+        * <p>
+        * Annotations are searched in the following orders:
+        * <ol>
+        *      <li>On the package of this class.
+        *      <li>On interfaces ordered parent-to-child.
+        *      <li>On parent classes ordered parent-to-child.
+        *      <li>On this class.
+        * </ol>
+        *
+        * @param annotationProvider The annotation provider.
+        * @param type The annotation to look for.
+        * @param filter A predicate to apply to the entries to determine if 
annotation should be returned.  Can be <jk>null</jk>.
+        * @return This object.
+        */
+       public <A extends Annotation> A firstAnnotation(AnnotationProvider 
annotationProvider, Class<A> type, Predicate<A> filter) {
+               if (annotationProvider == null)
+                       annotationProvider = AnnotationProvider.DEFAULT;
+               A x = null;
+               x = getPackageAnnotation(type);
+               if (x != null && passes(filter, x))
+                       return x;
+               ClassInfo[] interfaces = _getInterfaces();
+               for (int i = interfaces.length-1; i >= 0; i--) {
+                       x = annotationProvider.firstAnnotation(type, 
interfaces[i].inner(), filter);
+                       if (x != null)
+                               return x;
+               }
+               ClassInfo[] parents = _getParents();
+               for (int i = parents.length-1; i >= 0; i--) {
+                       x = annotationProvider.firstAnnotation(type, 
parents[i].inner(), filter);
+                       if (x != null)
+                               return x;
+               }
+               return null;
+       }
+
+       /**
+        * Returns the last matching annotation on this class and 
superclasses/interfaces.
+        *
+        * <p>
+        * Annotations are searched in the following orders:
+        * <ol>
+        *      <li>On this class.
+        *      <li>On parent classes ordered child-to-parent.
+        *      <li>On interfaces ordered child-to-parent.
+        *      <li>On the package of this class.
+        * </ol>
+        *
+        * @param type The annotation to look for.
+        * @param filter A predicate to apply to the entries to determine if 
annotation should be returned.  Can be <jk>null</jk>.
+        * @return This object.
+        */
+       public <A extends Annotation> A lastAnnotation(Class<A> type, 
Predicate<A> filter) {
+               return lastAnnotation(null, type, filter);
+       }
+
+       /**
+        * Returns the last matching annotation on this class and 
superclasses/interfaces.
+        *
+        * <p>
+        * Annotations are searched in the following orders:
+        * <ol>
+        *      <li>On this class.
+        *      <li>On parent classes ordered child-to-parent.
+        *      <li>On interfaces ordered child-to-parent.
+        *      <li>On the package of this class.
+        * </ol>
+        *
+        * @param annotationProvider The annotation provider.
+        * @param type The annotation to look for.
+        * @param filter A predicate to apply to the entries to determine if 
annotation should be returned.  Can be <jk>null</jk>.
+        * @return This object.
+        */
+       public <A extends Annotation> A lastAnnotation(AnnotationProvider 
annotationProvider, Class<A> type, Predicate<A> filter) {
+               if (annotationProvider == null)
+                       annotationProvider = AnnotationProvider.DEFAULT;
+               A x = null;
+               ClassInfo[] parents = _getParents();
+               for (int i = 0; i < parents.length; i++) {
+                       x = annotationProvider.lastAnnotation(type, 
parents[i].inner(), filter);
+                       if (x != null)
+                               return x;
+               }
+               ClassInfo[] interfaces = _getInterfaces();
+               for (int i = 0; i < interfaces.length; i++) {
+                       x = annotationProvider.lastAnnotation(type, 
interfaces[i].inner(), filter);
+                       if (x != null)
+                               return x;
+               }
+               x = getPackageAnnotation(type);
+               if (x != null && passes(filter, x))
+                       return x;
+               return null;
+       }
+
+       /**
         * Finds the annotation of the specified type defined on this class or 
parent class/interface.
         *
         * <p>
@@ -1001,7 +1117,7 @@ public final class ClassInfo {
         * @return The annotation if found, or <jk>null</jk> if not.
         */
        public <A extends Annotation> A getAnnotation(Class<A> type) {
-               return getAnnotation(AnnotationProvider.DEFAULT, type);
+               return getAnnotation(null, type);
        }
 
        /**
@@ -1026,7 +1142,7 @@ public final class ClassInfo {
         * @return The <jk>true</jk> if annotation if found.
         */
        public <A extends Annotation> boolean hasAnnotation(Class<A> type) {
-               return hasAnnotation(AnnotationProvider.DEFAULT, type);
+               return hasAnnotation(null, type);
        }
 
        /**
@@ -1047,6 +1163,8 @@ public final class ClassInfo {
         * @return The <jk>true</jk> if annotation if found.
         */
        public <A extends Annotation> boolean hasAnnotation(AnnotationProvider 
annotationProvider, Class<A> type) {
+               if (annotationProvider == null)
+                       annotationProvider = AnnotationProvider.DEFAULT;
                return annotationProvider.firstAnnotation(type, c, x -> true) 
!= null;
        }
 
@@ -1070,7 +1188,7 @@ public final class ClassInfo {
         * @return This object.
         */
        public <A extends Annotation> A getAnnotation(Class<A> type, 
Predicate<A> filter) {
-               return getAnnotation(AnnotationProvider.DEFAULT, type, filter);
+               return getAnnotation(null, type, filter);
        }
 
        /**
@@ -1133,6 +1251,8 @@ public final class ClassInfo {
        private <A extends Annotation> A findAnnotation(AnnotationProvider ap, 
Class<A> a) {
                if (a == null)
                        return null;
+               if (ap == null)
+                       ap = AnnotationProvider.DEFAULT;
                A t = ap.firstDeclaredAnnotation(a, c, x -> true);
                if (t != null)
                        return t;
@@ -1151,6 +1271,8 @@ public final class ClassInfo {
        }
 
        private <A extends Annotation> A getAnnotation(AnnotationProvider ap, 
Class<A> a, Predicate<A> filter) {
+               if (ap == null)
+                       ap = AnnotationProvider.DEFAULT;
                A t2 = getPackageAnnotation(a);
                if (t2 != null && filter.test(t2))
                        return t2;
diff --git a/juneau-utest/src/test/java/org/apache/juneau/ClassMetaTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/ClassMetaTest.java
index d6bb88a..d382d16 100755
--- a/juneau-utest/src/test/java/org/apache/juneau/ClassMetaTest.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/ClassMetaTest.java
@@ -12,11 +12,14 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau;
 
+import static org.apache.juneau.internal.CollectionUtils.*;
 import static org.junit.Assert.*;
 import static org.junit.runners.MethodSorters.*;
+import static org.apache.juneau.assertions.Assertions.*;
 
 import java.util.*;
 
+import org.apache.juneau.reflect.ClassInfoTest.*;
 import org.apache.juneau.swap.*;
 import org.junit.*;
 
@@ -26,13 +29,14 @@ public class ClassMetaTest {
 
        BeanContext bc = BeanContext.DEFAULT;
 
-       
//====================================================================================================
-       // Map<String,String> field
-       
//====================================================================================================
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Basic tests
+       
//-----------------------------------------------------------------------------------------------------------------
+
        public Map<String,String> fa;
 
        @Test
-       public void testMap() throws Exception {
+       public void a01_map() throws Exception {
                ClassMeta t = 
bc.getClassMeta(this.getClass().getField("fa").getGenericType());
                
assertEquals("java.util.Map<java.lang.String,java.lang.String>", t.toString());
                assertTrue(t.isMap());
@@ -43,77 +47,72 @@ public class ClassMetaTest {
                assertEquals(String.class, t.getValueType().getInnerClass());
        }
 
-       
//====================================================================================================
-       // String field
-       
//====================================================================================================
        public String fb;
 
        @Test
-       public void testString() throws Exception {
+       public void a02_string() throws Exception {
                ClassMeta t = 
bc.getClassMeta(this.getClass().getField("fb").getGenericType());
                assertEquals(String.class, t.getInnerClass());
                t = bc.getClassMeta(this.getClass().getField("fb").getType());
                assertEquals(String.class, t.getInnerClass());
        }
 
-       
//====================================================================================================
-       // Map<String,Map<String,Integer>> field
-       
//====================================================================================================
        public Map<String,Map<String,Integer>> fc;
 
        @Test
-       public void testMapWithMapValues() throws Exception {
+       public void a03_mapWithMapValues() throws Exception {
                ClassMeta t = 
bc.getClassMeta(this.getClass().getField("fc").getGenericType());
                
assertEquals("java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.Integer>>",
 t.toString());
                t = bc.getClassMeta(this.getClass().getField("fc").getType());
                assertEquals("java.util.Map", t.toString());
        }
 
-       
//====================================================================================================
-       // List<Map<String,List>> field
-       
//====================================================================================================
        public List<Map<String,List>> fd;
 
        @Test
-       public void testListWithMapValues() throws Exception {
+       public void a04_listWithMapValues() throws Exception {
                ClassMeta t = 
bc.getClassMeta(this.getClass().getField("fd").getGenericType());
                
assertEquals("java.util.List<java.util.Map<java.lang.String,java.util.List>>", 
t.toString());
        }
 
-       
//====================================================================================================
-       // List<? extends String> field, List<? super String> field
-       
//====================================================================================================
        public List<? extends String> fe1;
        public List<? super String> fe2;
 
        @Test
-       public void testListWithUpperBoundGenericEntryTypes() throws Exception {
+       public void a05_listWithUpperBoundGenericEntryTypes() throws Exception {
                ClassMeta t = 
bc.getClassMeta(this.getClass().getField("fe1").getGenericType());
                assertEquals("java.util.List", t.toString());
                t = 
bc.getClassMeta(this.getClass().getField("fe2").getGenericType());
                assertEquals("java.util.List", t.toString());
        }
 
-       
//====================================================================================================
-       // Bean extends HashMap<String,Object> field
-       
//====================================================================================================
        public class G extends HashMap<String,Object> {}
        public G g;
 
        @Test
-       public void testBeanExtendsMap() throws Exception {
+       public void a06_beanExtendsMap() throws Exception {
                ClassMeta t = 
bc.getClassMeta(this.getClass().getField("g").getGenericType());
                
assertEquals("org.apache.juneau.ClassMetaTest$G<java.lang.String,java.lang.Object>",
 t.toString());
                assertTrue(t.isMap());
                assertFalse(t.isCollection());
        }
 
-       
//====================================================================================================
-       // testSwaps
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Swaps
        // Ensure swaps on parent and child classes are properly detected.
-       
//====================================================================================================
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       public interface BI1 {}
+       public class BC1 implements BI1 {}
+       public interface BI2 extends BI1 {}
+       public class BC2 extends BC1 implements BI2 {}
+       public static class BC1Swap extends ObjectSwap<BC1,Map> {}
+       public static class BI1Swap extends ObjectSwap<BI1,Map> {}
+       public static class BC2Swap extends ObjectSwap<BC2,Map> {}
+       public static class BI2Swap extends ObjectSwap<BI2,Map> {}
+
        @Test
-       public void testSwaps() throws Exception {
+       public void b01_swaps() throws Exception {
                BeanContext bc;
                ClassMeta<?> ooo, hi1, hc1, hi2, hc2;
                BeanSession bs;
@@ -121,10 +120,10 @@ public class ClassMetaTest {
                bc = BeanContext.DEFAULT;
                bs = bc.getSession();
                ooo = bc.getClassMeta(Object.class);
-               hi1 = bc.getClassMeta(HI1.class);
-               hc1 = bc.getClassMeta(HC1.class);
-               hi2 = bc.getClassMeta(HI2.class);
-               hc2 = bc.getClassMeta(HC2.class);
+               hi1 = bc.getClassMeta(BI1.class);
+               hc1 = bc.getClassMeta(BC1.class);
+               hi2 = bc.getClassMeta(BI2.class);
+               hc2 = bc.getClassMeta(BC2.class);
                assertFalse(ooo.hasChildSwaps());
                assertFalse(hi1.hasChildSwaps());
                assertFalse(hc1.hasChildSwaps());
@@ -136,41 +135,41 @@ public class ClassMetaTest {
                assertNull(hi2.getSwap(bs));
                assertNull(hc2.getSwap(bs));
                assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), 
Object.class);
-               assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
HI1.class);
-               assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
HC1.class);
-               assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
HI2.class);
-               assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), 
HC2.class);
+               assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
BI1.class);
+               assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
BC1.class);
+               assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
BI2.class);
+               assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), 
BC2.class);
 
-               bc = BeanContext.create().swaps(HI1Swap.class).build();
+               bc = BeanContext.create().swaps(BI1Swap.class).build();
                bs = bc.getSession();
                ooo = bc.getClassMeta(Object.class);
-               hi1 = bc.getClassMeta(HI1.class);
-               hc1 = bc.getClassMeta(HC1.class);
-               hi2 = bc.getClassMeta(HI2.class);
-               hc2 = bc.getClassMeta(HC2.class);
+               hi1 = bc.getClassMeta(BI1.class);
+               hc1 = bc.getClassMeta(BC1.class);
+               hi2 = bc.getClassMeta(BI2.class);
+               hc2 = bc.getClassMeta(BC2.class);
                assertTrue(ooo.hasChildSwaps());
                assertTrue(hi1.hasChildSwaps());
                assertFalse(hc1.hasChildSwaps());
                assertFalse(hi2.hasChildSwaps());
                assertFalse(hc2.hasChildSwaps());
                assertNull(ooo.getSwap(bs));
-               assertEquals(hi1.getSwap(bs).getClass(), HI1Swap.class);
-               assertEquals(hc1.getSwap(bs).getClass(), HI1Swap.class);
-               assertEquals(hi2.getSwap(bs).getClass(), HI1Swap.class);
-               assertEquals(hc2.getSwap(bs).getClass(), HI1Swap.class);
+               assertEquals(hi1.getSwap(bs).getClass(), BI1Swap.class);
+               assertEquals(hc1.getSwap(bs).getClass(), BI1Swap.class);
+               assertEquals(hi2.getSwap(bs).getClass(), BI1Swap.class);
+               assertEquals(hc2.getSwap(bs).getClass(), BI1Swap.class);
                assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), 
Object.class);
                assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
                assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
                assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
                assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
 
-               bc = BeanContext.create().swaps(HC1Swap.class).build();
+               bc = BeanContext.create().swaps(BC1Swap.class).build();
                bs = bc.getSession();
                ooo = bc.getClassMeta(Object.class);
-               hi1 = bc.getClassMeta(HI1.class);
-               hc1 = bc.getClassMeta(HC1.class);
-               hi2 = bc.getClassMeta(HI2.class);
-               hc2 = bc.getClassMeta(HC2.class);
+               hi1 = bc.getClassMeta(BI1.class);
+               hc1 = bc.getClassMeta(BC1.class);
+               hi2 = bc.getClassMeta(BI2.class);
+               hc2 = bc.getClassMeta(BC2.class);
                assertTrue(ooo.hasChildSwaps());
                assertTrue(hi1.hasChildSwaps());
                assertTrue(hc1.hasChildSwaps());
@@ -178,22 +177,22 @@ public class ClassMetaTest {
                assertFalse(hc2.hasChildSwaps());
                assertNull(ooo.getSwap(bs));
                assertNull(hi1.getSwap(bs));
-               assertEquals(hc1.getSwap(bs).getClass(), HC1Swap.class);
+               assertEquals(hc1.getSwap(bs).getClass(), BC1Swap.class);
                assertNull(hi2.getSwap(bs));
-               assertEquals(hc2.getSwap(bs).getClass(), HC1Swap.class);
+               assertEquals(hc2.getSwap(bs).getClass(), BC1Swap.class);
                assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), 
Object.class);
-               assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
HI1.class);
+               assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
BI1.class);
                assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
-               assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
HI2.class);
+               assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
BI2.class);
                assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
 
-               bc = BeanContext.create().swaps(HI2Swap.class).build();
+               bc = BeanContext.create().swaps(BI2Swap.class).build();
                bs = bc.getSession();
                ooo = bc.getClassMeta(Object.class);
-               hi1 = bc.getClassMeta(HI1.class);
-               hc1 = bc.getClassMeta(HC1.class);
-               hi2 = bc.getClassMeta(HI2.class);
-               hc2 = bc.getClassMeta(HC2.class);
+               hi1 = bc.getClassMeta(BI1.class);
+               hc1 = bc.getClassMeta(BC1.class);
+               hi2 = bc.getClassMeta(BI2.class);
+               hc2 = bc.getClassMeta(BC2.class);
                assertTrue(ooo.hasChildSwaps());
                assertTrue(hi1.hasChildSwaps());
                assertFalse(hc1.hasChildSwaps());
@@ -202,21 +201,21 @@ public class ClassMetaTest {
                assertNull(ooo.getSwap(bs));
                assertNull(hi1.getSwap(bs));
                assertNull(hc1.getSwap(bs));
-               assertEquals(hi2.getSwap(bs).getClass(), HI2Swap.class);
-               assertEquals(hc2.getSwap(bs).getClass(), HI2Swap.class);
+               assertEquals(hi2.getSwap(bs).getClass(), BI2Swap.class);
+               assertEquals(hc2.getSwap(bs).getClass(), BI2Swap.class);
                assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), 
Object.class);
-               assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
HI1.class);
-               assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
HC1.class);
+               assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
BI1.class);
+               assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
BC1.class);
                assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
                assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
 
-               bc = BeanContext.create().swaps(HC2Swap.class).build();
+               bc = BeanContext.create().swaps(BC2Swap.class).build();
                bs = bc.getSession();
                ooo = bc.getClassMeta(Object.class);
-               hi1 = bc.getClassMeta(HI1.class);
-               hc1 = bc.getClassMeta(HC1.class);
-               hi2 = bc.getClassMeta(HI2.class);
-               hc2 = bc.getClassMeta(HC2.class);
+               hi1 = bc.getClassMeta(BI1.class);
+               hc1 = bc.getClassMeta(BC1.class);
+               hi2 = bc.getClassMeta(BI2.class);
+               hc2 = bc.getClassMeta(BC2.class);
                assertTrue(ooo.hasChildSwaps());
                assertTrue(hi1.hasChildSwaps());
                assertTrue(hc1.hasChildSwaps());
@@ -226,53 +225,53 @@ public class ClassMetaTest {
                assertNull(hi1.getSwap(bs));
                assertNull(hc1.getSwap(bs));
                assertNull(hi2.getSwap(bs));
-               assertEquals(hc2.getSwap(bs).getClass(), HC2Swap.class);
+               assertEquals(hc2.getSwap(bs).getClass(), BC2Swap.class);
                assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), 
Object.class);
-               assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
HI1.class);
-               assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
HC1.class);
-               assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
HI2.class);
+               assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
BI1.class);
+               assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
BC1.class);
+               assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
BI2.class);
                assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
 
-               bc = 
BeanContext.create().swaps(HI1Swap.class,HC1Swap.class,HI2Swap.class, 
HC2Swap.class).build();
+               bc = 
BeanContext.create().swaps(BI1Swap.class,BC1Swap.class,BI2Swap.class, 
BC2Swap.class).build();
                bs = bc.getSession();
                ooo = bc.getClassMeta(Object.class);
-               hi1 = bc.getClassMeta(HI1.class);
-               hc1 = bc.getClassMeta(HC1.class);
-               hi2 = bc.getClassMeta(HI2.class);
-               hc2 = bc.getClassMeta(HC2.class);
+               hi1 = bc.getClassMeta(BI1.class);
+               hc1 = bc.getClassMeta(BC1.class);
+               hi2 = bc.getClassMeta(BI2.class);
+               hc2 = bc.getClassMeta(BC2.class);
                assertTrue(ooo.hasChildSwaps());
                assertTrue(hi1.hasChildSwaps());
                assertTrue(hc1.hasChildSwaps());
                assertTrue(hi2.hasChildSwaps());
                assertTrue(hc2.hasChildSwaps());
                assertNull(ooo.getSwap(bs));
-               assertEquals(hi1.getSwap(bs).getClass(), HI1Swap.class);
-               assertEquals(hc1.getSwap(bs).getClass(), HI1Swap.class);
-               assertEquals(hi2.getSwap(bs).getClass(), HI1Swap.class);
-               assertEquals(hc2.getSwap(bs).getClass(), HI1Swap.class);
+               assertEquals(hi1.getSwap(bs).getClass(), BI1Swap.class);
+               assertEquals(hc1.getSwap(bs).getClass(), BI1Swap.class);
+               assertEquals(hi2.getSwap(bs).getClass(), BI1Swap.class);
+               assertEquals(hc2.getSwap(bs).getClass(), BI1Swap.class);
                assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), 
Object.class);
                assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
                assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
                assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
                assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
 
-               bc = 
BeanContext.create().swaps(HC2Swap.class,HI2Swap.class,HC1Swap.class, 
HI1Swap.class).build();
+               bc = 
BeanContext.create().swaps(BC2Swap.class,BI2Swap.class,BC1Swap.class, 
BI1Swap.class).build();
                bs = bc.getSession();
                ooo = bc.getClassMeta(Object.class);
-               hi1 = bc.getClassMeta(HI1.class);
-               hc1 = bc.getClassMeta(HC1.class);
-               hi2 = bc.getClassMeta(HI2.class);
-               hc2 = bc.getClassMeta(HC2.class);
+               hi1 = bc.getClassMeta(BI1.class);
+               hc1 = bc.getClassMeta(BC1.class);
+               hi2 = bc.getClassMeta(BI2.class);
+               hc2 = bc.getClassMeta(BC2.class);
                assertTrue(ooo.hasChildSwaps());
                assertTrue(hi1.hasChildSwaps());
                assertTrue(hc1.hasChildSwaps());
                assertTrue(hi2.hasChildSwaps());
                assertTrue(hc2.hasChildSwaps());
                assertNull(ooo.getSwap(bs));
-               assertEquals(hi1.getSwap(bs).getClass(), HI1Swap.class);
-               assertEquals(hc1.getSwap(bs).getClass(), HC1Swap.class);
-               assertEquals(hi2.getSwap(bs).getClass(), HI2Swap.class);
-               assertEquals(hc2.getSwap(bs).getClass(), HC2Swap.class);
+               assertEquals(hi1.getSwap(bs).getClass(), BI1Swap.class);
+               assertEquals(hc1.getSwap(bs).getClass(), BC1Swap.class);
+               assertEquals(hi2.getSwap(bs).getClass(), BI2Swap.class);
+               assertEquals(hc2.getSwap(bs).getClass(), BC2Swap.class);
                assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), 
Object.class);
                assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
                assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
@@ -280,12 +279,61 @@ public class ClassMetaTest {
                assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), 
Map.class);
        }
 
-       public interface HI1 {}
-       public class HC1 implements HI1 {}
-       public interface HI2 extends HI1 {}
-       public class HC2 extends HC1 implements HI2 {}
-       public static class HC1Swap extends ObjectSwap<HC1,Map> {}
-       public static class HI1Swap extends ObjectSwap<HI1,Map> {}
-       public static class HC2Swap extends ObjectSwap<HC2,Map> {}
-       public static class HI2Swap extends ObjectSwap<HI2,Map> {}
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Annotations
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @A(1) static interface CI1 {}
+       @A(2) static interface CI2 extends CI1 {}
+       @A(3) static interface CI3 {}
+       @A(4) static interface CI4 {}
+       @A(5) static class C1 implements CI1, CI2 {}
+       @A(6) static class C2 extends C1 implements CI3 {}
+       @A(7) static class C3 extends C2 {}
+       static class C4 extends C3 {}
+       static class C5 implements CI3 {}
+
+       @Test
+       public void forEachAnnotation() {
+               ClassMeta<?> c3 = bc.getClassMeta(C3.class);
+               ClassMeta<?> c4 = bc.getClassMeta(C4.class);
+               ClassMeta<?> c5 = bc.getClassMeta(C5.class);
+
+               List<Integer> l1 = list();
+               c3.forEachAnnotation(A.class, null, x -> l1.add(x.value()));
+               assertList(l1).asCdl().isString("2,1,3,5,6,7");
+
+               List<Integer> l2 = list();
+               c4.forEachAnnotation(A.class, null, x -> l2.add(x.value()));
+               assertList(l2).asCdl().isString("2,1,3,5,6,7");
+
+               List<Integer> l3 = list();
+               c5.forEachAnnotation(A.class, null, x -> l3.add(x.value()));
+               assertList(l3).asCdl().isString("3");
+
+               List<Integer> l4 = list();
+               c3.forEachAnnotation(A.class, x -> x.value() == 5, x -> 
l4.add(x.value()));
+               assertList(l4).asCdl().isString("5");
+       }
+
+       @Test
+       public void firstAnnotation() {
+               ClassMeta<?> c3 = bc.getClassMeta(C3.class);
+               ClassMeta<?> c4 = bc.getClassMeta(C4.class);
+               ClassMeta<?> c5 = bc.getClassMeta(C5.class);
+               assertInteger(c3.firstAnnotation(A.class, 
null).get().value()).is(2);
+               assertInteger(c4.firstAnnotation(A.class, 
null).get().value()).is(2);
+               assertInteger(c5.firstAnnotation(A.class, 
null).get().value()).is(3);
+               assertInteger(c3.firstAnnotation(A.class, x -> x.value() == 
5).get().value()).is(5);
+       }
+       @Test
+       public void lastAnnotation() {
+               ClassMeta<?> c3 = bc.getClassMeta(C3.class);
+               ClassMeta<?> c4 = bc.getClassMeta(C4.class);
+               ClassMeta<?> c5 = bc.getClassMeta(C5.class);
+               assertInteger(c3.lastAnnotation(A.class, 
null).get().value()).is(7);
+               assertInteger(c4.lastAnnotation(A.class, 
null).get().value()).is(7);
+               assertInteger(c5.lastAnnotation(A.class, 
null).get().value()).is(3);
+               assertInteger(c3.lastAnnotation(A.class, x -> x.value() == 
5).get().value()).is(5);
+       }
 }
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/reflect/ClassInfoTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/reflect/ClassInfoTest.java
index 993154f..0ed2efd 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/reflect/ClassInfoTest.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/reflect/ClassInfoTest.java
@@ -625,8 +625,44 @@ public class ClassInfoTest {
        }
 
        @Test
-       public void getAnnotationsParentFirst() {
+       public void getAnnotations() {
                check("@A(2),@A(1),@A(3),@A(5),@A(6),@A(7)", 
g3.getAnnotations(A.class));
+               check("@A(2),@A(1),@A(3),@A(5),@A(6),@A(7)", 
g4.getAnnotations(A.class));
+               check("@A(3)", g5.getAnnotations(A.class));
+       }
+
+       @Test
+       public void forEachAnnotation() {
+               List<Integer> l1 = list();
+               g3.forEachAnnotation(A.class, null, x -> l1.add(x.value()));
+               assertList(l1).asCdl().isString("2,1,3,5,6,7");
+
+               List<Integer> l2 = list();
+               g4.forEachAnnotation(A.class, null, x -> l2.add(x.value()));
+               assertList(l2).asCdl().isString("2,1,3,5,6,7");
+
+               List<Integer> l3 = list();
+               g5.forEachAnnotation(A.class, null, x -> l3.add(x.value()));
+               assertList(l3).asCdl().isString("3");
+
+               List<Integer> l4 = list();
+               g3.forEachAnnotation(A.class, x -> x.value() == 5, x -> 
l4.add(x.value()));
+               assertList(l4).asCdl().isString("5");
+       }
+
+       @Test
+       public void firstAnnotation() {
+               assertInteger(g3.firstAnnotation(A.class, null).value()).is(2);
+               assertInteger(g4.firstAnnotation(A.class, null).value()).is(2);
+               assertInteger(g5.firstAnnotation(A.class, null).value()).is(3);
+               assertInteger(g3.firstAnnotation(A.class, x -> x.value() == 
5).value()).is(5);
+       }
+       @Test
+       public void lastAnnotation() {
+               assertInteger(g3.lastAnnotation(A.class, null).value()).is(7);
+               assertInteger(g4.lastAnnotation(A.class, null).value()).is(7);
+               assertInteger(g5.lastAnnotation(A.class, null).value()).is(3);
+               assertInteger(g3.lastAnnotation(A.class, x -> x.value() == 
5).value()).is(5);
        }
 
        @Test

Reply via email to