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 12873e4  JUNEAU-197
12873e4 is described below

commit 12873e4cdb789dcfbfb605849b8065c759aa2334
Author: JamesBognar <[email protected]>
AuthorDate: Sun Mar 8 13:36:57 2020 -0400

    JUNEAU-197
    
    @BeanConfig(bpi) does not override @Bean(bpi)
---
 .../juneau/internal/ReadOnlyArrayListTest.java     | 142 +++++++
 .../apache/juneau/reflection/ClassInfoTest.java    |  28 +-
 .../main/java/org/apache/juneau/BeanContext.java   |   8 +-
 .../main/java/org/apache/juneau/ContextCache.java  |   2 +-
 .../apache/juneau/internal/ReadOnlyArrayList.java  | 217 +++++++++++
 .../java/org/apache/juneau/reflect/ClassInfo.java  | 406 ++++++++++++---------
 .../java/org/apache/juneau/reflect/Mutaters.java   |   2 +-
 .../org/apache/juneau/transform/DefaultSwaps.java  |   2 +-
 8 files changed, 613 insertions(+), 194 deletions(-)

diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/internal/ReadOnlyArrayListTest.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/internal/ReadOnlyArrayListTest.java
new file mode 100644
index 0000000..cdb4e8d
--- /dev/null
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/internal/ReadOnlyArrayListTest.java
@@ -0,0 +1,142 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.internal;
+
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.junit.*;
+
+@SuppressWarnings("unchecked")
+public class ReadOnlyArrayListTest {
+
+       private static <T> ReadOnlyArrayList<T> create(T...t) {
+               return new ReadOnlyArrayList<>(t);
+       }
+
+       private static <T> ReadOnlyArrayList<T> createReversed(T...t) {
+               return new ReadOnlyArrayList<>(t, true);
+       }
+
+       @Test
+       public void testBasic() {
+               List<String> l = create("a","b","c");
+               assertEquals("a", l.get(0));
+               assertEquals("b", l.get(1));
+               assertEquals("c", l.get(2));
+       }
+
+       @Test
+       public void testBasicReversed() {
+               List<String> l = createReversed("a","b","c");
+               assertEquals("c", l.get(0));
+               assertEquals("b", l.get(1));
+               assertEquals("a", l.get(2));
+       }
+
+       @Test
+       public void testIterator() {
+               List<String> l = create("a","b","c");
+               Iterator<String> i = l.iterator();
+               assertTrue(i.hasNext());
+               assertEquals("a", i.next());
+               assertTrue(i.hasNext());
+               assertEquals("b", i.next());
+               assertTrue(i.hasNext());
+               assertEquals("c", i.next());
+               assertFalse(i.hasNext());
+
+               l = create();
+               assertFalse(l.iterator().hasNext());
+       }
+
+       @Test
+       public void testIteratorReversed() {
+               List<String> l = createReversed("a","b","c");
+               Iterator<String> i = l.iterator();
+               assertTrue(i.hasNext());
+               assertEquals("c", i.next());
+               assertTrue(i.hasNext());
+               assertEquals("b", i.next());
+               assertTrue(i.hasNext());
+               assertEquals("a", i.next());
+               assertFalse(i.hasNext());
+
+               l = createReversed();
+               assertFalse(l.iterator().hasNext());
+       }
+
+       @Test
+       public void testSize() {
+               assertEquals(1, create("a").size());
+       }
+
+       @Test
+       public void testIsEmpty() {
+               assertFalse(create("a").isEmpty());
+               assertTrue(create().isEmpty());
+       }
+
+       @Test
+       public void testContains() {
+               assertTrue(create("a").contains("a"));
+               assertFalse(create("a").contains("b"));
+               assertFalse(create("a").contains(null));
+               assertTrue(create("a", null).contains(null));
+       }
+
+       @Test
+       public void testToArray() {
+               String[] s = new String[]{"a"};
+               List<String> l = new ReadOnlyArrayList<>(s);
+               String[] s2 = (String[])l.toArray();
+               assertEquals("a", s2[0]);
+               s2[0] = "b";
+               assertEquals("a", s[0]);
+       }
+
+       @Test
+       public void testToArray2() {
+               String[] s = new String[]{"a"};
+               List<String> l = new ReadOnlyArrayList<>(s);
+               String[] s2 = l.toArray(new String[l.size()]);
+               assertEquals("a", s2[0]);
+               s2[0] = "b";
+               assertEquals("a", s[0]);
+       }
+
+       @Test
+       public void testContainsAll() {
+               assertTrue(create("a").containsAll(Arrays.asList("a")));
+               assertFalse(create("a").containsAll(Arrays.asList("a","b")));
+               assertFalse(create("a").containsAll(Arrays.asList("b")));
+               
assertFalse(create("a").containsAll(Arrays.asList((String)null)));
+               assertTrue(create("a", 
null).containsAll(Arrays.asList((String)null)));
+       }
+
+       @Test
+       public void testIndexOf() {
+               List<String> l = create("a","b","a","c");
+               assertEquals(0, l.indexOf("a"));
+               assertEquals(2, l.lastIndexOf("a"));
+               assertEquals(1, l.indexOf("b"));
+               assertEquals(1, l.lastIndexOf("b"));
+               assertEquals(3, l.indexOf("c"));
+               assertEquals(3, l.lastIndexOf("c"));
+               assertEquals(-1, l.indexOf("d"));
+               assertEquals(-1, l.lastIndexOf("d"));
+               assertEquals(-1, l.indexOf(null));
+               assertEquals(-1, l.lastIndexOf(null));
+       }
+}
diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
index ed52125..1f60dca 100644
--- 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
@@ -215,23 +215,23 @@ public class ClassInfoTest {
 
        @Test
        public void getInterfaces() {
-               check("", bi4.getInterfaces());
-               check("BI1,BI2", bc1.getInterfaces());
-               check("BI3,BI1,BI2", bc2.getInterfaces());
-               check("BI3,BI1,BI2", bc3.getInterfaces());
+               check("", bi4.getInterfacesChildFirst());
+               check("BI1,BI2", bc1.getInterfacesChildFirst());
+               check("BI3,BI1,BI2", bc2.getInterfacesChildFirst());
+               check("BI3,BI1,BI2", bc3.getInterfacesChildFirst());
        }
 
        @Test
        public void getInterfaces_tiwce() {
-               check("BI3,BI1,BI2", bc2.getInterfaces());
-               check("BI3,BI1,BI2", bc2.getInterfaces());
+               check("BI3,BI1,BI2", bc2.getInterfacesChildFirst());
+               check("BI3,BI1,BI2", bc2.getInterfacesChildFirst());
        }
 
        @Test
        public void getParents() {
-               check("BC3,BC2,BC1", bc3.getParents());
-               check("", object.getParents());
-               check("BI1", bi1.getParents());
+               check("BC3,BC2,BC1", bc3.getParentsChildFirst());
+               check("", object.getParentsChildFirst());
+               check("BI1", bi1.getParentsChildFirst());
        }
 
        @Test
@@ -243,15 +243,15 @@ public class ClassInfoTest {
 
        @Test
        public void getAllParents() {
-               check("BC3,BC2,BC1,BI3,BI1,BI2", bc3.getAllParents());
-               check("", object.getAllParents());
-               check("BI1", bi1.getAllParents());
+               check("BC3,BC2,BC1,BI3,BI1,BI2", bc3.getAllParentsChildFirst());
+               check("", object.getAllParentsChildFirst());
+               check("BI1", bi1.getAllParentsChildFirst());
        }
 
        @Test
        public void getAllParents_twice() {
-               check("BC3,BC2,BC1,BI3,BI1,BI2", bc3.getAllParents());
-               check("BC3,BC2,BC1,BI3,BI1,BI2", bc3.getAllParents());
+               check("BC3,BC2,BC1,BI3,BI1,BI2", bc3.getAllParentsChildFirst());
+               check("BC3,BC2,BC1,BI3,BI1,BI2", bc3.getAllParentsChildFirst());
        }
 
        @Test
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 309841e..0fb6e53 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -3638,7 +3638,7 @@ public class BeanContext extends Context implements 
MetaProvider {
                if (bpi.isEmpty())
                        return emptySet();
                ClassInfo ci = ClassInfo.of(c);
-               for (ClassInfo c2 : ci.getAllParents()) {
+               for (ClassInfo c2 : ci.getAllParentsChildFirst()) {
                        for (String n : c2.getNames()) {
                                Set<String> s = bpi.get(n);
                                if (s != null)
@@ -3671,7 +3671,7 @@ public class BeanContext extends Context implements 
MetaProvider {
                if (bpx.isEmpty())
                        return emptySet();
                ClassInfo ci = ClassInfo.of(c);
-               for (ClassInfo c2 : ci.getAllParents()) {
+               for (ClassInfo c2 : ci.getAllParentsChildFirst()) {
                        for (String n : c2.getNames()) {
                                Set<String> s = bpx.get(n);
                                if (s != null)
@@ -3704,7 +3704,7 @@ public class BeanContext extends Context implements 
MetaProvider {
                if (bpro.isEmpty())
                        return emptySet();
                ClassInfo ci = ClassInfo.of(c);
-               for (ClassInfo c2 : ci.getAllParents()) {
+               for (ClassInfo c2 : ci.getAllParentsChildFirst()) {
                        for (String n : c2.getNames()) {
                                Set<String> s = bpro.get(n);
                                if (s != null)
@@ -3737,7 +3737,7 @@ public class BeanContext extends Context implements 
MetaProvider {
                if (bpwo.isEmpty())
                        return emptySet();
                ClassInfo ci = ClassInfo.of(c);
-               for (ClassInfo c2 : ci.getAllParents()) {
+               for (ClassInfo c2 : ci.getAllParentsChildFirst()) {
                        for (String n : c2.getNames()) {
                                Set<String> s = bpwo.get(n);
                                if (s != null)
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextCache.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextCache.java
index 18856aa..0ca4716 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextCache.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextCache.java
@@ -146,7 +146,7 @@ public class ContextCache {
                String[] prefixes = prefixCache.get(c);
                if (prefixes == null) {
                        Set<String> ps = new HashSet<>();
-                       for (ClassInfo c2 : ClassInfo.of(c).getAllParents()) {
+                       for (ClassInfo c2 : 
ClassInfo.of(c).getAllParentsChildFirst()) {
                                ConfigurableContext cc = 
c2.getLastAnnotation(ConfigurableContext.class);
                                if (cc != null) {
                                        if (cc.nocache()) {
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ReadOnlyArrayList.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ReadOnlyArrayList.java
new file mode 100644
index 0000000..28c165a
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ReadOnlyArrayList.java
@@ -0,0 +1,217 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.internal;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * Simple read-only wrapper around an object array.
+ *
+ * <p>
+ * Allows for forward or reverse access to elements of an array without being 
able to modify the array and without
+ * involving copying the array.
+ *
+ * @param <T> Array element type.
+ */
+public class ReadOnlyArrayList<T> implements List<T> {
+
+       final T[] array;
+       final int length;
+       private final boolean reversed;
+
+       /**
+        * Constructor.
+        *
+        * @param array The array being wrapped.
+        */
+       public ReadOnlyArrayList(T[] array) {
+               this(array, false);
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param array The array being wrapped.
+        * @param reversed <jk>true</jk> if elements of array should be 
addressed in reverse.
+        */
+       @SuppressWarnings("unchecked")
+       public ReadOnlyArrayList(T[] array, boolean reversed) {
+               this.array = array == null ? (T[])new Object[0] : array;
+               this.length = this.array.length;
+               this.reversed = reversed;
+       }
+
+       @Override
+       public int size() {
+               return array.length;
+       }
+
+       @Override
+       public boolean isEmpty() {
+               return array.length == 0;
+       }
+
+       @Override
+       public boolean contains(Object o) {
+               return indexOf(o) != -1;
+       }
+
+       @Override
+       public Iterator<T> iterator() {
+               if (reversed) {
+                       return new Iterator<T>() {
+                               int i = length-1;
+
+                               @Override
+                               public boolean hasNext() {
+                                       return i > -1;
+                               }
+
+                               @Override
+                               public T next() {
+                                       return array[i--];
+                               }
+                       };
+               }
+               return new Iterator<T>() {
+                       int i = 0;
+
+                       @Override
+                       public boolean hasNext() {
+                               return i < length;
+                       }
+
+                       @Override
+                       public T next() {
+                               return array[i++];
+                       }
+               };
+       }
+
+       @Override
+       public Object[] toArray() {
+               Object[] o2 = 
(Object[])Array.newInstance(array.getClass().getComponentType(), array.length);
+               for (int i = 0; i < array.length; i++)
+                       o2[i] = reversed ? array[length-i-1] : array[i];
+               return o2;
+       }
+
+       @Override
+       @SuppressWarnings({ "unchecked", "hiding" })
+       public <T> T[] toArray(T[] a) {
+               for (int i = 0; i < array.length; i++)
+                       a[i] = reversed ? (T)array[length-i-1] : (T)array[i];
+               return a;
+       }
+
+       @Override
+       public boolean add(T e) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public boolean remove(Object o) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public boolean containsAll(Collection<?> c) {
+               for (Object o : c)
+                       if (! contains(o))
+                               return false;
+               return true;
+       }
+
+       @Override
+       public boolean addAll(Collection<? extends T> c) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public boolean addAll(int index, Collection<? extends T> c) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public boolean removeAll(Collection<?> c) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public boolean retainAll(Collection<?> c) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public void clear() {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public T get(int index) {
+               return reversed ? array[length-index-1] : array[index];
+       }
+
+       @Override
+       public T set(int index, T element) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public void add(int index, T element) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public T remove(int index) {
+               throw new UnsupportedOperationException("Cannot modify 
read-only list.");
+       }
+
+       @Override
+       public int indexOf(Object o) {
+               for (int i = 0; i < length; i++) {
+                       int j = reversed ? length-i-1 : i;
+                       T t = array[j];
+                       if ((o == t) || (o != null && o.equals(t)))
+                               return j;
+               }
+               return -1;
+       }
+
+       @Override
+       public int lastIndexOf(Object o) {
+               for (int i = length-1; i >= 0; i--) {
+                       int j = reversed ? length-i-1 : i;
+                       T t = array[j];
+                       if ((o == t) || (o != null && o.equals(t)))
+                               return j;
+               }
+               return -1;
+       }
+
+       @Override
+       public ListIterator<T> listIterator() {
+               throw new UnsupportedOperationException("Unsupported method on 
ReadOnlyArrayList class.");
+       }
+
+       @Override
+       public ListIterator<T> listIterator(int index) {
+               throw new UnsupportedOperationException("Unsupported method on 
ReadOnlyArrayList class.");
+       }
+
+       @Override
+       public List<T> subList(int fromIndex, int toIndex) {
+               throw new UnsupportedOperationException("Unsupported method on 
ReadOnlyArrayList class.");
+       }
+}
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 f0df106..c3fcc9c 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
@@ -60,10 +60,10 @@ public final class ClassInfo {
        final Class<?> c;
        private ClassInfo proxyFor;
        private final boolean isParameterizedType;
-       private List<ClassInfo> interfaces, declaredInterfaces, parents, 
allParents;
-       private List<MethodInfo> publicMethods, declaredMethods, allMethods, 
allMethodsParentFirst;
-       private List<ConstructorInfo> publicConstructors, declaredConstructors;
-       private List<FieldInfo> publicFields, declaredFields, allFields, 
allFieldsParentFirst;
+       private ClassInfo[] interfaces, declaredInterfaces, parents, allParents;
+       private MethodInfo[] publicMethods, declaredMethods, allMethods, 
allMethodsParentFirst;
+       private ConstructorInfo[] publicConstructors, declaredConstructors;
+       private FieldInfo[] publicFields, declaredFields, allFields, 
allFieldsParentFirst;
        private int dim = -1;
        private ClassInfo componentType;
 
@@ -249,14 +249,7 @@ public final class ClassInfo {
         *      <br>Results are in the same order as {@link 
Class#getInterfaces()}.
         */
        public List<ClassInfo> getDeclaredInterfaces() {
-               if (declaredInterfaces == null) {
-                       Class<?>[] ii = c == null ? new Class[0] : 
c.getInterfaces();
-                       List<ClassInfo> l = new ArrayList<>(ii.length);
-                       for (Class<?> i : ii)
-                               l.add(of(i));
-                       declaredInterfaces = unmodifiableList(l);
-               }
-               return declaredInterfaces;
+               return new ReadOnlyArrayList<>(getDeclaredInterfacesInternal());
        }
 
        /**
@@ -266,18 +259,8 @@ public final class ClassInfo {
         *      An unmodifiable list of interfaces defined on this class and 
superclasses.
         *      <br>Results are in child-to-parent order.
         */
-       public List<ClassInfo> getInterfaces() {
-               if (interfaces == null) {
-                       Set<ClassInfo> s = new LinkedHashSet<>();
-                       for (ClassInfo ci : getParents())
-                               for (ClassInfo ci2 : 
ci.getDeclaredInterfaces()) {
-                                       s.add(ci2);
-                                       for (ClassInfo ci3 : 
ci2.getInterfaces())
-                                               s.add(ci3);
-                               }
-                       interfaces = unmodifiableList(new ArrayList<>(s));
-               }
-               return interfaces;
+       public List<ClassInfo> getInterfacesChildFirst() {
+               return new ReadOnlyArrayList<>(getInterfacesInternal());
        }
 
        /**
@@ -287,8 +270,8 @@ public final class ClassInfo {
         *      An unmodifiable list of interfaces defined on this class and 
superclasses.
         *      <br>Results are in parent-to-child order.
         */
-       public Iterable<ClassInfo> getInterfacesParentFirst() {
-               return iterable(getInterfaces(), true);
+       public List<ClassInfo> getInterfacesParentFirst() {
+               return new ReadOnlyArrayList<>(getInterfacesInternal(), true);
        }
 
        /**
@@ -300,17 +283,8 @@ public final class ClassInfo {
         * @return An unmodifiable list including this class and all parent 
classes.
         *      <br>Results are in child-to-parent order.
         */
-       public List<ClassInfo> getParents() {
-               if (parents == null) {
-                       List<ClassInfo> l = new ArrayList<>();
-                       Class<?> pc = c;
-                       while (pc != null && pc != Object.class) {
-                               l.add(of(pc));
-                               pc = pc.getSuperclass();
-                       }
-                       parents = Collections.unmodifiableList(l);
-               }
-               return parents;
+       public List<ClassInfo> getParentsChildFirst() {
+               return new ReadOnlyArrayList<>(getParentsInternal());
        }
 
        /**
@@ -322,8 +296,8 @@ public final class ClassInfo {
         * @return An unmodifiable list including this class and all parent 
classes.
         *      <br>Results are in parent-to-child order.
         */
-       public Iterable<ClassInfo> getParentsParentFirst() {
-               return iterable(getParents(), true);
+       public List<ClassInfo> getParentsParentFirst() {
+               return new ReadOnlyArrayList<>(getParentsInternal(), true);
        }
 
        /**
@@ -332,14 +306,8 @@ public final class ClassInfo {
         * @return An unmodifiable list including this class and all parent 
classes.
         *      <br>Results are ordered child-to-parent order with classes 
listed before interfaces.
         */
-       public List<ClassInfo> getAllParents() {
-               if (allParents == null) {
-                       List<ClassInfo> l = new ArrayList<>();
-                       l.addAll(getParents());
-                       l.addAll(getInterfaces());
-                       allParents = Collections.unmodifiableList(l);
-               }
-               return allParents;
+       public List<ClassInfo> getAllParentsChildFirst() {
+               return new ReadOnlyArrayList<>(getAllParentsInternal());
        }
 
        /**
@@ -348,8 +316,59 @@ public final class ClassInfo {
         * @return An unmodifiable list including this class and all parent 
classes.
         *      <br>Results are ordered parent-to-child order with interfaces 
listed before classes.
         */
-       public Iterable<ClassInfo> getAllParentsParentFirst() {
-               return iterable(getAllParents(), true);
+       public List<ClassInfo> getAllParentsParentFirst() {
+               return new ReadOnlyArrayList<>(getAllParentsInternal(), true);
+       }
+
+       private ClassInfo[] getInterfacesInternal() {
+               if (interfaces == null) {
+                       Set<ClassInfo> s = new LinkedHashSet<>();
+                       for (ClassInfo ci : getParentsChildFirst())
+                               for (ClassInfo ci2 : 
ci.getDeclaredInterfaces()) {
+                                       s.add(ci2);
+                                       for (ClassInfo ci3 : 
ci2.getInterfacesChildFirst())
+                                               s.add(ci3);
+                               }
+                       interfaces = s.toArray(new ClassInfo[s.size()]);
+               }
+               return interfaces;
+       }
+
+       private ClassInfo[] getDeclaredInterfacesInternal() {
+               if (declaredInterfaces == null) {
+                       Class<?>[] ii = c == null ? new Class[0] : 
c.getInterfaces();
+                       ClassInfo[] l = new ClassInfo[ii.length];
+                       for (int i = 0; i < ii.length; i++)
+                               l[i] = of(ii[i]);
+                       declaredInterfaces = l;
+               }
+               return declaredInterfaces;
+       }
+
+       private ClassInfo[] getParentsInternal() {
+               if (parents == null) {
+                       List<ClassInfo> l = new ArrayList<>();
+                       Class<?> pc = c;
+                       while (pc != null && pc != Object.class) {
+                               l.add(of(pc));
+                               pc = pc.getSuperclass();
+                       }
+                       parents = l.toArray(new ClassInfo[l.size()]);
+               }
+               return parents;
+       }
+
+       private ClassInfo[] getAllParentsInternal() {
+               if (allParents == null) {
+                       ClassInfo[] a1 = getParentsInternal(), a2 = 
getInterfacesInternal();
+                       ClassInfo[] l = new ClassInfo[a1.length + a2.length];
+                       for (int i = 0; i < a1.length; i++)
+                               l[i] = a1[i];
+                       for (int i = 0; i < a2.length; i++)
+                               l[i+a1.length] = a2[i];
+                       allParents = l;
+               }
+               return allParents;
        }
 
        
//-----------------------------------------------------------------------------------------------------------------
@@ -367,34 +386,7 @@ public final class ClassInfo {
         *      <br>Results are ordered alphabetically.
         */
        public List<MethodInfo> getPublicMethods() {
-               if (publicMethods == null) {
-                       Method[] mm = c == null ? new Method[0] : 
c.getMethods();
-                       List<MethodInfo> l = new ArrayList<>(mm.length);
-                       for (Method m : mm)
-                               if (m.getDeclaringClass() != Object.class)
-                                       l.add(MethodInfo.of(this, m, 
getProxyTarget(m)));
-                       l.sort(null);
-                       publicMethods = Collections.unmodifiableList(l);
-               }
-               return publicMethods;
-       }
-
-       private Method getProxyTarget(Method m) {
-               if (proxyFor != null) {
-                       MethodInfo m2 = proxyFor.getMethod(m.getName(), 
m.getParameterTypes());
-                       if (m2 != null)
-                               return m2.inner();
-               }
-               return m;
-       }
-
-       private Constructor<?> getProxyTarget(Constructor<?> c) {
-               if (proxyFor != null) {
-                       ConstructorInfo c2 = 
proxyFor.getConstructor(Visibility.PRIVATE, c.getParameterTypes());
-                       if (c2 != null)
-                               return c2.inner();
-               }
-               return c;
+               return new ReadOnlyArrayList<>(getPublicMethodsInternal());
        }
 
        /**
@@ -406,7 +398,7 @@ public final class ClassInfo {
         *  The public method with the specified method name and argument 
types, or <jk>null</jk> if not found.
         */
        public MethodInfo getPublicMethod(String name, Class<?>...args) {
-               for (MethodInfo mi : getPublicMethods())
+               for (MethodInfo mi : getPublicMethodsInternal())
                        if (mi.hasName(name) && mi.hasParamTypes(args))
                                return mi;
                return null;
@@ -421,7 +413,7 @@ public final class ClassInfo {
         *  The method with the specified method name and argument types, or 
<jk>null</jk> if not found.
         */
        public MethodInfo getMethod(String name, Class<?>...args) {
-               for (MethodInfo mi : getAllMethods())
+               for (MethodInfo mi : getAllMethodsInternal())
                        if (mi.hasName(name) && mi.hasParamTypes(args))
                                return mi;
                return null;
@@ -435,16 +427,7 @@ public final class ClassInfo {
         *      <br>Results are ordered alphabetically.
         */
        public List<MethodInfo> getDeclaredMethods() {
-               if (declaredMethods == null) {
-                       Method[] mm = c == null ? new Method[0] : 
c.getDeclaredMethods();
-                       List<MethodInfo> l = new ArrayList<>(mm.length);
-                       for (Method m : mm)
-                               if (! "$jacocoInit".equals(m.getName())) // 
Jacoco adds its own simulated methods.
-                                       l.add(MethodInfo.of(this, m, 
getProxyTarget(m)));
-                       l.sort(null);
-                       declaredMethods = Collections.unmodifiableList(l);
-               }
-               return declaredMethods;
+               return new ReadOnlyArrayList<>(getDeclaredMethodsInternal());
        }
 
        /**
@@ -455,13 +438,7 @@ public final class ClassInfo {
         *      <br>Results are ordered child-to-parent, and then 
alphabetically per class.
         */
        public List<MethodInfo> getAllMethods() {
-               if (allMethods == null) {
-                       List<MethodInfo> l = new ArrayList<>();
-                       for (ClassInfo c : getAllParents())
-                               c.appendDeclaredMethods(l);
-                       allMethods = Collections.unmodifiableList(l);
-               }
-               return allMethods;
+               return new ReadOnlyArrayList<>(getAllMethodsInternal());
        }
 
        /**
@@ -473,11 +450,51 @@ public final class ClassInfo {
         *      <br>Results are ordered parent-to-child, and then 
alphabetically per class.
         */
        public List<MethodInfo> getAllMethodsParentFirst() {
+               return new 
ReadOnlyArrayList<>(getAllMethodsParentFirstInternal());
+       }
+
+       private MethodInfo[] getPublicMethodsInternal() {
+               if (publicMethods == null) {
+                       Method[] mm = c == null ? new Method[0] : 
c.getMethods();
+                       List<MethodInfo> l = new ArrayList<>(mm.length);
+                       for (Method m : mm)
+                               if (m.getDeclaringClass() != Object.class)
+                                       l.add(MethodInfo.of(this, m, 
getProxyTarget(m)));
+                       l.sort(null);
+                       publicMethods = l.toArray(new MethodInfo[l.size()]);
+               }
+               return publicMethods;
+       }
+
+       private MethodInfo[] getDeclaredMethodsInternal() {
+               if (declaredMethods == null) {
+                       Method[] mm = c == null ? new Method[0] : 
c.getDeclaredMethods();
+                       List<MethodInfo> l = new ArrayList<>(mm.length);
+                       for (Method m : mm)
+                               if (! "$jacocoInit".equals(m.getName())) // 
Jacoco adds its own simulated methods.
+                                       l.add(MethodInfo.of(this, m, 
getProxyTarget(m)));
+                       l.sort(null);
+                       declaredMethods = l.toArray(new MethodInfo[l.size()]);
+               }
+               return declaredMethods;
+       }
+
+       private MethodInfo[] getAllMethodsInternal() {
+               if (allMethods == null) {
+                       List<MethodInfo> l = new ArrayList<>();
+                       for (ClassInfo c : getAllParentsChildFirst())
+                               c.appendDeclaredMethods(l);
+                       allMethods = l.toArray(new MethodInfo[l.size()]);
+               }
+               return allMethods;
+       }
+
+       private MethodInfo[] getAllMethodsParentFirstInternal() {
                if (allMethodsParentFirst == null) {
                        List<MethodInfo> l = new ArrayList<>();
                        for (ClassInfo c : getAllParentsParentFirst())
                                c.appendDeclaredMethods(l);
-                       allMethodsParentFirst = Collections.unmodifiableList(l);
+                       allMethodsParentFirst = l.toArray(new 
MethodInfo[l.size()]);
                }
                return allMethodsParentFirst;
        }
@@ -487,6 +504,24 @@ public final class ClassInfo {
                return l;
        }
 
+       private Method getProxyTarget(Method m) {
+               if (proxyFor != null) {
+                       MethodInfo m2 = proxyFor.getMethod(m.getName(), 
m.getParameterTypes());
+                       if (m2 != null)
+                               return m2.inner();
+               }
+               return m;
+       }
+
+       private Constructor<?> getProxyTarget(Constructor<?> c) {
+               if (proxyFor != null) {
+                       ConstructorInfo c2 = 
proxyFor.getConstructor(Visibility.PRIVATE, c.getParameterTypes());
+                       if (c2 != null)
+                               return c2.inner();
+               }
+               return c;
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Special methods
        
//-----------------------------------------------------------------------------------------------------------------
@@ -594,15 +629,7 @@ public final class ClassInfo {
         * @return All public constructors defined on this class.
         */
        public List<ConstructorInfo> getPublicConstructors() {
-               if (publicConstructors == null) {
-                       Constructor<?>[] cc = c == null ? new Constructor[0] : 
c.getConstructors();
-                       List<ConstructorInfo> l = new ArrayList<>(cc.length);
-                       for (Constructor<?> ccc : cc)
-                               l.add(ConstructorInfo.of(this, ccc, 
getProxyTarget(ccc)));
-                       l.sort(null);
-                       publicConstructors = Collections.unmodifiableList(l);
-               }
-               return publicConstructors;
+               return new ReadOnlyArrayList<>(getPublicConstructorsInternal());
        }
 
        /**
@@ -613,7 +640,7 @@ public final class ClassInfo {
         *  The public constructor with the specified argument types, or 
<jk>null</jk> if not found.
         */
        public ConstructorInfo getPublicConstructor(Class<?>...args) {
-               for (ConstructorInfo ci : getPublicConstructors())
+               for (ConstructorInfo ci : getPublicConstructorsInternal())
                        if (ci.hasParamTypes(args))
                                return ci;
                return null;
@@ -627,7 +654,7 @@ public final class ClassInfo {
         *  The declared constructor with the specified argument types, or 
<jk>null</jk> if not found.
         */
        public ConstructorInfo getDeclaredConstructor(Class<?>...args) {
-               for (ConstructorInfo ci : getDeclaredConstructors())
+               for (ConstructorInfo ci : getDeclaredConstructorsInternal())
                        if (ci.hasParamTypes(args))
                                return ci;
                return null;
@@ -653,15 +680,7 @@ public final class ClassInfo {
         * @return All constructors defined on this class.
         */
        public List<ConstructorInfo> getDeclaredConstructors() {
-               if (declaredConstructors == null) {
-                       Constructor<?>[] cc = c == null ? new Constructor[0] : 
c.getDeclaredConstructors();
-                       List<ConstructorInfo> l = new ArrayList<>(cc.length);
-                       for (Constructor<?> ccc : cc)
-                               l.add(ConstructorInfo.of(this, ccc, 
getProxyTarget(ccc)));
-                       l.sort(null);
-                       declaredConstructors = Collections.unmodifiableList(l);
-               }
-               return declaredConstructors;
+               return new 
ReadOnlyArrayList<>(getDeclaredConstructorsInternal());
        }
 
        /**
@@ -701,11 +720,35 @@ public final class ClassInfo {
                return getConstructor(vis, false, argTypes);
        }
 
+       private ConstructorInfo[] getPublicConstructorsInternal() {
+               if (publicConstructors == null) {
+                       Constructor<?>[] cc = c == null ? new Constructor[0] : 
c.getConstructors();
+                       List<ConstructorInfo> l = new ArrayList<>(cc.length);
+                       for (Constructor<?> ccc : cc)
+                               l.add(ConstructorInfo.of(this, ccc, 
getProxyTarget(ccc)));
+                       l.sort(null);
+                       publicConstructors = l.toArray(new 
ConstructorInfo[l.size()]);
+               }
+               return publicConstructors;
+       }
+
+       private ConstructorInfo[] getDeclaredConstructorsInternal() {
+               if (declaredConstructors == null) {
+                       Constructor<?>[] cc = c == null ? new Constructor[0] : 
c.getDeclaredConstructors();
+                       List<ConstructorInfo> l = new ArrayList<>(cc.length);
+                       for (Constructor<?> ccc : cc)
+                               l.add(ConstructorInfo.of(this, ccc, 
getProxyTarget(ccc)));
+                       l.sort(null);
+                       declaredConstructors = l.toArray(new 
ConstructorInfo[l.size()]);
+               }
+               return declaredConstructors;
+       }
+
        private ConstructorInfo getConstructor(Visibility vis, boolean 
fuzzyArgs, Class<?>...argTypes) {
                if (fuzzyArgs) {
                        int bestCount = -1;
                        ConstructorInfo bestMatch = null;
-                       for (ConstructorInfo n : getDeclaredConstructors()) {
+                       for (ConstructorInfo n : 
getDeclaredConstructorsInternal()) {
                                if (vis.isVisible(n.inner())) {
                                        int m = 
ClassUtils.fuzzyArgsMatch(n.getParamTypes(), argTypes);
                                        if (m > bestCount) {
@@ -718,7 +761,7 @@ public final class ClassInfo {
                }
 
                boolean isMemberClass = isNonStaticMemberClass();
-               for (ConstructorInfo n : getDeclaredConstructors()) {
+               for (ConstructorInfo n : getDeclaredConstructorsInternal()) {
                        List<ClassInfo> paramTypes = n.getParamTypes();
                        if (isMemberClass)
                                paramTypes = paramTypes.subList(1, 
paramTypes.size());
@@ -748,7 +791,7 @@ public final class ClassInfo {
                if (isAbstract())
                        return null;
                boolean isMemberClass = isNonStaticMemberClass();
-               for (ConstructorInfo cc : getDeclaredConstructors())
+               for (ConstructorInfo cc : getDeclaredConstructorsInternal())
                        if (cc.hasNumParams(isMemberClass ? 1 : 0) && 
cc.isVisible(v))
                                return cc.makeAccessible(v);
                return null;
@@ -769,15 +812,7 @@ public final class ClassInfo {
         *      <br>Results are in alphabetical order.
         */
        public List<FieldInfo> getPublicFields() {
-               if (publicFields == null) {
-                       Map<String,FieldInfo> m = new LinkedHashMap<>();
-                       for (ClassInfo c : getParents())
-                               c.appendDeclaredPublicFields(m);
-                       List<FieldInfo> l = new ArrayList<>(m.values());
-                       l.sort(null);
-                       publicFields = Collections.unmodifiableList(l);
-               }
-               return publicFields;
+               return new ReadOnlyArrayList<>(getPublicFieldsInternal());
        }
 
        /**
@@ -788,16 +823,7 @@ public final class ClassInfo {
         *      <br>Results are in alphabetical order.
         */
        public List<FieldInfo> getDeclaredFields() {
-               if (declaredFields == null) {
-                       Field[] ff = c == null ? new Field[0] : 
c.getDeclaredFields();
-                       List<FieldInfo> l = new ArrayList<>(ff.length);
-                       for (Field f : ff)
-                               if (! "$jacocoData".equals(f.getName()))
-                                       l.add(FieldInfo.of(this, f));
-                       l.sort(null);
-                       declaredFields = Collections.unmodifiableList(l);
-               }
-               return declaredFields;
+               return new ReadOnlyArrayList<>(getDeclaredFieldsInternal());
        }
 
        /**
@@ -808,13 +834,7 @@ public final class ClassInfo {
         *      <br>Results are ordered child-to-parent, and then alphabetical 
per class.
         */
        public List<FieldInfo> getAllFields() {
-               if (allFields == null) {
-                       List<FieldInfo> l = new ArrayList<>();
-                       for (ClassInfo c : getAllParents())
-                               c.appendDeclaredFields(l);
-                       allFields = Collections.unmodifiableList(l);
-               }
-               return allFields;
+               return new ReadOnlyArrayList<>(getAllFieldsInternal());
        }
 
        /**
@@ -825,27 +845,7 @@ public final class ClassInfo {
         *      <br>Results are ordered parent-to-child, and then alphabetical 
per class.
         */
        public List<FieldInfo> getAllFieldsParentFirst() {
-               if (allFieldsParentFirst == null) {
-                       List<FieldInfo> l = new ArrayList<>();
-                       for (ClassInfo c : getAllParentsParentFirst())
-                               c.appendDeclaredFields(l);
-                       allFieldsParentFirst = Collections.unmodifiableList(l);
-               }
-               return allFieldsParentFirst;
-       }
-
-       private List<FieldInfo> appendDeclaredFields(List<FieldInfo> l) {
-               l.addAll(getDeclaredFields());
-               return l;
-       }
-
-       private Map<String,FieldInfo> 
appendDeclaredPublicFields(Map<String,FieldInfo> m) {
-               for (FieldInfo f : getDeclaredFields()) {
-                       String fn = f.getName();
-                       if (f.isPublic() && ! (m.containsKey(fn) || 
"$jacocoData".equals(fn)))
-                                       m.put(f.getName(), f);
-               }
-               return m;
+               return new 
ReadOnlyArrayList<>(getAllFieldsParentFirstInternal());
        }
 
        /**
@@ -855,7 +855,7 @@ public final class ClassInfo {
         * @return The public field, or <jk>null</jk> if not found.
         */
        public FieldInfo getPublicField(String name) {
-               for (FieldInfo f : getPublicFields())
+               for (FieldInfo f : getPublicFieldsInternal())
                        if (f.getName().equals(name))
                                return f;
                return null;
@@ -868,7 +868,7 @@ public final class ClassInfo {
         * @return The declared field, or <jk>null</jk> if not found.
         */
        public FieldInfo getDeclaredField(String name) {
-               for (FieldInfo f : getDeclaredFields())
+               for (FieldInfo f : getDeclaredFieldsInternal())
                        if (f.getName().equals(name))
                                return f;
                return null;
@@ -881,7 +881,7 @@ public final class ClassInfo {
         * @return The public field, or <jk>null</jk> if not found.
         */
        public FieldInfo getStaticPublicField(String name) {
-               for (FieldInfo f : getPublicFields())
+               for (FieldInfo f : getPublicFieldsInternal())
                        if (f.isStatic() && f.getName().equals(name))
                                return f;
                return null;
@@ -894,12 +894,72 @@ public final class ClassInfo {
         * @return The public field, or <jk>null</jk> if not found.
         */
        public Field getStaticPublicFieldInner(String name) {
-               for (FieldInfo f : getPublicFields())
+               for (FieldInfo f : getPublicFieldsInternal())
                        if (f.isStatic() && f.getName().equals(name))
                                return f.inner();
                return null;
        }
 
+       private List<FieldInfo> appendDeclaredFields(List<FieldInfo> l) {
+               for (FieldInfo f : getDeclaredFieldsInternal())
+                       l.add(f);
+               return l;
+       }
+
+       private Map<String,FieldInfo> 
appendDeclaredPublicFields(Map<String,FieldInfo> m) {
+               for (FieldInfo f : getDeclaredFieldsInternal()) {
+                       String fn = f.getName();
+                       if (f.isPublic() && ! (m.containsKey(fn) || 
"$jacocoData".equals(fn)))
+                                       m.put(f.getName(), f);
+               }
+               return m;
+       }
+
+       private FieldInfo[] getPublicFieldsInternal() {
+               if (publicFields == null) {
+                       Map<String,FieldInfo> m = new LinkedHashMap<>();
+                       for (ClassInfo c : getParentsInternal())
+                               c.appendDeclaredPublicFields(m);
+                       List<FieldInfo> l = new ArrayList<>(m.values());
+                       l.sort(null);
+                       publicFields = l.toArray(new FieldInfo[l.size()]);
+               }
+               return publicFields;
+       }
+
+       private FieldInfo[] getDeclaredFieldsInternal() {
+               if (declaredFields == null) {
+                       Field[] ff = c == null ? new Field[0] : 
c.getDeclaredFields();
+                       List<FieldInfo> l = new ArrayList<>(ff.length);
+                       for (Field f : ff)
+                               if (! "$jacocoData".equals(f.getName()))
+                                       l.add(FieldInfo.of(this, f));
+                       l.sort(null);
+                       declaredFields = l.toArray(new FieldInfo[l.size()]);
+               }
+               return declaredFields;
+       }
+
+       private FieldInfo[] getAllFieldsInternal() {
+               if (allFields == null) {
+                       List<FieldInfo> l = new ArrayList<>();
+                       for (ClassInfo c : getAllParentsInternal())
+                               c.appendDeclaredFields(l);
+                       allFields = l.toArray(new FieldInfo[l.size()]);
+               }
+               return allFields;
+       }
+       
+       private FieldInfo[] getAllFieldsParentFirstInternal() {
+               if (allFieldsParentFirst == null) {
+                       List<FieldInfo> l = new ArrayList<>();
+                       for (ClassInfo c : getAllParentsParentFirst())
+                               c.appendDeclaredFields(l);
+                       allFieldsParentFirst = l.toArray(new 
FieldInfo[l.size()]);
+               }
+               return allFieldsParentFirst;
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Annotations
        
//-----------------------------------------------------------------------------------------------------------------
@@ -1185,7 +1245,7 @@ public final class ClassInfo {
                        if (x != null)
                                return x;
                }
-               for (ClassInfo ci : getInterfaces()) {
+               for (ClassInfo ci : getInterfacesChildFirst()) {
                        for (Class<? extends Annotation> ca : annotations) {
                                Annotation x = ci.getLastAnnotation(ca, mp);
                                if (x != null)
@@ -1226,7 +1286,7 @@ public final class ClassInfo {
                                return t2;
                }
 
-               for (ClassInfo c2 : getInterfaces()) {
+               for (ClassInfo c2 : getInterfacesChildFirst()) {
                        t2 = c2.getLastAnnotation(a, mp);
                        if (t2 != null)
                                return t2;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/Mutaters.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/Mutaters.java
index c45e52b..9a50054 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/Mutaters.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/Mutaters.java
@@ -147,7 +147,7 @@ public class Mutaters {
 
                ClassInfo ici = ClassInfo.of(ic), oci = ClassInfo.of(oc);
 
-               for (ClassInfo pic : ici.getAllParents()) {
+               for (ClassInfo pic : ici.getAllParentsChildFirst()) {
                        Mutater t = m.get(pic.inner());
                        if (t != null)
                                return t;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DefaultSwaps.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DefaultSwaps.java
index 7334bb7..143e806 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DefaultSwaps.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DefaultSwaps.java
@@ -60,7 +60,7 @@ public class DefaultSwaps {
         * @return The matched swap, or <jk>null</jk> if it couldn't be found.
         */
        public static PojoSwap<?,?> find(ClassInfo ci) {
-               for (ClassInfo ci2 : ci.getAllParents()) {
+               for (ClassInfo ci2 : ci.getAllParentsChildFirst()) {
                        PojoSwap<?,?> ps = POJO_SWAPS.get(ci2.inner());
                        if (ps != null)
                                return ps;

Reply via email to