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 9a2a81d  ClassInfo refactoring.
9a2a81d is described below

commit 9a2a81d4d8370199a08206c0ccc95556951f97ef
Author: JamesBognar <[email protected]>
AuthorDate: Sun Jan 30 10:41:54 2022 -0500

    ClassInfo refactoring.
---
 .../java/org/apache/juneau/AnnotationProvider.java |  36 +++-
 .../main/java/org/apache/juneau/BeanFilter.java    |   2 +-
 .../src/main/java/org/apache/juneau/Context.java   |  84 ++------
 .../juneau/internal/TwoKeyConcurrentCache.java     |  17 +-
 .../java/org/apache/juneau/reflect/ClassInfo.java  | 231 +++++++++++++--------
 .../org/apache/juneau/reflect/ConstructorInfo.java |  37 ++--
 .../org/apache/juneau/reflect/ExecutableInfo.java  |  95 +++++----
 .../java/org/apache/juneau/reflect/FieldInfo.java  |  48 +++--
 .../java/org/apache/juneau/reflect/MethodInfo.java |  55 +++--
 .../org/apache/juneau/utils/ReflectionMap.java     | 214 +++++++++++--------
 .../org/apache/juneau/utils/ReflectionMapTest.java |   8 +-
 11 files changed, 472 insertions(+), 355 deletions(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/AnnotationProvider.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/AnnotationProvider.java
index 953bb59..d8abcd8 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/AnnotationProvider.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/AnnotationProvider.java
@@ -16,6 +16,8 @@ import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.util.function.*;
 
+import org.apache.juneau.internal.*;
+
 /**
  * Interface that provides the ability to look up annotations on 
classes/methods/constructors/fields.
  *
@@ -26,14 +28,26 @@ import java.util.function.*;
 public interface AnnotationProvider {
 
        /**
+        * Disable annotation caching.
+        */
+       static final boolean DISABLE_ANNOTATION_CACHING = 
Boolean.getBoolean("juneau.disableAnnotationCaching");
+
+       /**
         * Default metadata provider.
         */
-       public static AnnotationProvider DEFAULT = new AnnotationProvider() {
+       @SuppressWarnings("unchecked")
+       public static final AnnotationProvider DEFAULT = new 
AnnotationProvider() {
+
+               private final TwoKeyConcurrentCache<Class<?>,Class<? extends 
Annotation>,Annotation[]> classAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, (k1,k2) -> 
k1.getAnnotationsByType(k2));
+               private final TwoKeyConcurrentCache<Class<?>,Class<? extends 
Annotation>,Annotation[]> declaredClassAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, (k1,k2) -> 
k1.getDeclaredAnnotationsByType(k2));
+               private final TwoKeyConcurrentCache<Method,Class<? extends 
Annotation>,Annotation[]> methodAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, (k1,k2) -> 
k1.getAnnotationsByType(k2));
+               private final TwoKeyConcurrentCache<Field,Class<? extends 
Annotation>,Annotation[]> fieldAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, (k1,k2) -> 
k1.getAnnotationsByType(k2));
+               private final TwoKeyConcurrentCache<Constructor<?>,Class<? 
extends Annotation>,Annotation[]> constructorAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, (k1,k2) -> 
k1.getAnnotationsByType(k2));
 
                @Override /* MetaProvider */
                public <A extends Annotation> void getAnnotations(Class<A> a, 
Class<?> c, Predicate<A> predicate, Consumer<A> consumer) {
                        if (a != null && c != null)
-                               for (A aa : c.getAnnotationsByType(a))
+                               for (A aa : (A[])classAnnotationCache.get(c,a))
                                        if (predicate.test(aa))
                                                consumer.accept(aa);
                }
@@ -41,7 +55,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> A getAnnotation(Class<A> a, 
Class<?> c, Predicate<A> predicate) {
                        if (a != null && c != null)
-                               for (A aa : c.getAnnotationsByType(a))
+                               for (A aa : (A[])classAnnotationCache.get(c,a))
                                        if (predicate.test(aa))
                                                return aa;
                        return null;
@@ -50,7 +64,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> void 
getDeclaredAnnotations(Class<A> a, Class<?> c, Predicate<A> predicate, 
Consumer<A> consumer) {
                        if (a != null && c != null)
-                               for (A aa : c.getDeclaredAnnotationsByType(a))
+                               for (A aa : 
(A[])declaredClassAnnotationCache.get(c,a))
                                        if (predicate.test(aa))
                                                consumer.accept(aa);
                }
@@ -58,7 +72,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> A getDeclaredAnnotation(Class<A> 
a, Class<?> c, Predicate<A> predicate) {
                        if (a != null && c != null)
-                               for (A aa : c.getDeclaredAnnotationsByType(a))
+                               for (A aa : 
(A[])declaredClassAnnotationCache.get(c,a))
                                        if (predicate.test(aa))
                                                return aa;
                        return null;
@@ -67,7 +81,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> void getAnnotations(Class<A> a, 
Method m, Predicate<A> predicate, Consumer<A> consumer) {
                        if (a != null && m != null)
-                               for (A aa : m.getAnnotationsByType(a))
+                               for (A aa : (A[])methodAnnotationCache.get(m,a))
                                        if (predicate.test(aa))
                                                consumer.accept(aa);
                }
@@ -75,7 +89,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> A getAnnotation(Class<A> a, 
Method m, Predicate<A> predicate) {
                        if (a != null && m != null)
-                               for (A aa : m.getAnnotationsByType(a))
+                               for (A aa : (A[])methodAnnotationCache.get(m,a))
                                        if (predicate.test(aa))
                                                return aa;
                        return null;
@@ -84,7 +98,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> void getAnnotations(Class<A> a, 
Field f, Predicate<A> predicate, Consumer<A> consumer) {
                        if (a != null && f != null)
-                               for (A aa : f.getAnnotationsByType(a))
+                               for (A aa : (A[])fieldAnnotationCache.get(f,a))
                                        if (predicate.test(aa))
                                                consumer.accept(aa);
                }
@@ -92,7 +106,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> A getAnnotation(Class<A> a, Field 
f, Predicate<A> predicate) {
                        if (a != null && f != null)
-                               for (A aa : f.getAnnotationsByType(a))
+                               for (A aa : (A[])fieldAnnotationCache.get(f,a))
                                        if (predicate.test(aa))
                                                return aa;
                        return null;
@@ -101,7 +115,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> void getAnnotations(Class<A> a, 
Constructor<?> c, Predicate<A> predicate, Consumer<A> consumer) {
                        if (a != null && c != null)
-                               for (A aa : c.getAnnotationsByType(a))
+                               for (A aa : 
(A[])constructorAnnotationCache.get(c,a))
                                        if (predicate.test(aa))
                                                consumer.accept(aa);
                }
@@ -109,7 +123,7 @@ public interface AnnotationProvider {
                @Override /* MetaProvider */
                public <A extends Annotation> A getAnnotation(Class<A> a, 
Constructor<?> c, Predicate<A> predicate) {
                        if (a != null && c != null)
-                               for (A aa : c.getAnnotationsByType(a))
+                               for (A aa : 
(A[])constructorAnnotationCache.get(c,a))
                                        if (predicate.test(aa))
                                                return aa;
                        return null;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanFilter.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanFilter.java
index 872d6ea..9453c72 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanFilter.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanFilter.java
@@ -659,7 +659,7 @@ public final class BeanFilter {
                 */
                public Builder dictionary(Class<?>...values) {
                        if (dictionary == null)
-                               dictionary = Arrays.asList(values);
+                               dictionary = new 
ArrayList<>(Arrays.asList(values));
                        else for (Class<?> cc : values)
                                dictionary.add(cc);
                        return this;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
index 1f6b98f..5d348e8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
@@ -820,6 +820,11 @@ public abstract class Context implements 
AnnotationProvider {
        final boolean debug;
 
        private final ReflectionMap<Annotation> annotationMap;
+       private final TwoKeyConcurrentCache<Class<?>,Class<? extends 
Annotation>,Annotation[]> classAnnotationCache;
+       private final TwoKeyConcurrentCache<Class<?>,Class<? extends 
Annotation>,Annotation[]> declaredClassAnnotationCache;
+       private final TwoKeyConcurrentCache<Method,Class<? extends 
Annotation>,Annotation[]> methodAnnotationCache;
+       private final TwoKeyConcurrentCache<Field,Class<? extends 
Annotation>,Annotation[]> fieldAnnotationCache;
+       private final TwoKeyConcurrentCache<Constructor<?>,Class<? extends 
Annotation>,Annotation[]> constructorAnnotationCache;
 
        /**
         * Copy constructor.
@@ -830,6 +835,11 @@ public abstract class Context implements 
AnnotationProvider {
                annotationMap = copyFrom.annotationMap;
                annotations = copyFrom.annotations;
                debug = copyFrom.debug;
+               classAnnotationCache = copyFrom.classAnnotationCache;
+               declaredClassAnnotationCache = 
copyFrom.declaredClassAnnotationCache;
+               methodAnnotationCache = copyFrom.methodAnnotationCache;
+               fieldAnnotationCache = copyFrom.fieldAnnotationCache;
+               constructorAnnotationCache = 
copyFrom.constructorAnnotationCache;
        }
 
        /**
@@ -868,6 +878,12 @@ public abstract class Context implements 
AnnotationProvider {
                        }
                }
                this.annotationMap = rmb.build();
+               boolean disabled = 
Boolean.getBoolean("juneau.disableAnnotationCaching");
+               classAnnotationCache = new TwoKeyConcurrentCache<>(disabled, 
(k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2)));
+               declaredClassAnnotationCache = new 
TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, 
k1.getDeclaredAnnotationsByType(k2)));
+               methodAnnotationCache = new TwoKeyConcurrentCache<>(disabled, 
(k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2)));
+               fieldAnnotationCache = new TwoKeyConcurrentCache<>(disabled, 
(k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2)));
+               constructorAnnotationCache = new 
TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, 
k1.getAnnotationsByType(k2)));
        }
 
        /**
@@ -926,14 +942,6 @@ public abstract class Context implements 
AnnotationProvider {
        // MetaProvider methods
        
//-----------------------------------------------------------------------------------------------------------------
 
-       private static final boolean DISABLE_ANNOTATION_CACHING = ! 
Boolean.getBoolean("juneau.disableAnnotationCaching");
-
-       private TwoKeyConcurrentCache<Class<?>,Class<? extends 
Annotation>,Annotation[]> classAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING);
-       private TwoKeyConcurrentCache<Class<?>,Class<? extends 
Annotation>,Annotation[]> declaredClassAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING);
-       private TwoKeyConcurrentCache<Method,Class<? extends 
Annotation>,Annotation[]> methodAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING);
-       private TwoKeyConcurrentCache<Field,Class<? extends 
Annotation>,Annotation[]> fieldAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING);
-       private TwoKeyConcurrentCache<Constructor<?>,Class<? extends 
Annotation>,Annotation[]> constructorAnnotationCache = new 
TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING);
-
        @Override /* MetaProvider */
        public <A extends Annotation> void getAnnotations(Class<A> a, Class<?> 
c, Predicate<A> predicate, Consumer<A> consumer) {
                if (a != null && c != null)
@@ -1065,77 +1073,27 @@ public abstract class Context implements 
AnnotationProvider {
 
        @SuppressWarnings("unchecked")
        private <A extends Annotation> A[] annotations(Class<A> a, Class<?> c) {
-               A[] aa = (A[])classAnnotationCache.get(c, a);
-               if (aa == null) {
-                       A[] x = c.getAnnotationsByType(a);
-                       AList<Annotation> l = new AList<>(Arrays.asList(x));
-                       annotationMap.appendAll(c, a, l);
-                       aa = (A[]) Array.newInstance(a, l.size());
-                       for (int i = 0; i < l.size(); i++)
-                               Array.set(aa, i, l.get(i));
-                       classAnnotationCache.put(c, a, aa);
-               }
-               return aa;
+               return (A[])classAnnotationCache.get(c, a);
        }
 
        @SuppressWarnings("unchecked")
        private <A extends Annotation> A[] declaredAnnotations(Class<A> a, 
Class<?> c) {
-               A[] aa = (A[])declaredClassAnnotationCache.get(c, a);
-               if (aa == null) {
-                       A[] x = c.getDeclaredAnnotationsByType(a);
-                       AList<Annotation> l = new AList<>(Arrays.asList(x));
-                       annotationMap.appendAll(c, a, l);
-                       aa = (A[]) Array.newInstance(a, l.size());
-                       for (int i = 0; i < l.size(); i++)
-                               Array.set(aa, i, l.get(i));
-                       declaredClassAnnotationCache.put(c, a, aa);
-               }
-               return aa;
+               return (A[])declaredClassAnnotationCache.get(c, a);
        }
 
        @SuppressWarnings("unchecked")
        private <A extends Annotation> A[] annotations(Class<A> a, Method m) {
-               A[] aa = (A[])methodAnnotationCache.get(m, a);
-               if (aa == null) {
-                       A[] x = m.getAnnotationsByType(a);
-                       AList<Annotation> l = new AList<>(Arrays.asList(x));
-                       annotationMap.appendAll(m, a, l);
-                       aa = (A[]) Array.newInstance(a, l.size());
-                       for (int i = 0; i < l.size(); i++)
-                               Array.set(aa, i, l.get(i));
-                       methodAnnotationCache.put(m, a, aa);
-               }
-               return aa;
+               return (A[])methodAnnotationCache.get(m, a);
        }
 
        @SuppressWarnings("unchecked")
        private <A extends Annotation> A[] annotations(Class<A> a, Field f) {
-               A[] aa = (A[])fieldAnnotationCache.get(f, a);
-               if (aa == null) {
-                       A[] x = f.getAnnotationsByType(a);
-                       AList<Annotation> l = new AList<>(Arrays.asList(x));
-                       annotationMap.appendAll(f, a, l);
-                       aa = (A[]) Array.newInstance(a, l.size());
-                       for (int i = 0; i < l.size(); i++)
-                               Array.set(aa, i, l.get(i));
-                       fieldAnnotationCache.put(f, a, aa);
-               }
-               return aa;
+               return (A[])fieldAnnotationCache.get(f, a);
        }
 
        @SuppressWarnings("unchecked")
        private <A extends Annotation> A[] annotations(Class<A> a, 
Constructor<?> c) {
-               A[] aa = (A[])constructorAnnotationCache.get(c, a);
-               if (aa == null) {
-                       A[] x = c.getAnnotationsByType(a);
-                       AList<Annotation> l = new AList<>(Arrays.asList(x));
-                       annotationMap.appendAll(c, a, l);
-                       aa = (A[]) Array.newInstance(a, l.size());
-                       for (int i = 0; i < l.size(); i++)
-                               Array.set(aa, i, l.get(i));
-                       constructorAnnotationCache.put(c, a, aa);
-               }
-               return aa;
+               return (A[])constructorAnnotationCache.get(c, a);
        }
 
        
//-----------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/TwoKeyConcurrentCache.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/TwoKeyConcurrentCache.java
index 6ab6345..7e3dae8 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/TwoKeyConcurrentCache.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/TwoKeyConcurrentCache.java
@@ -14,6 +14,7 @@ package org.apache.juneau.internal;
 
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.function.*;
 
 /**
  * A hashmap that allows for two-part keys.
@@ -31,20 +32,23 @@ public class TwoKeyConcurrentCache<K1,K2,V> extends 
ConcurrentHashMap<TwoKeyConc
        private static final long serialVersionUID = 1L;
 
        private final boolean disabled;
+       private final BiFunction<K1,K2,V> supplier;
 
        /**
         * Constructor.
         */
        public TwoKeyConcurrentCache() {
-               this.disabled = false;
+               this(false, null);
        }
 
        /**
         * Constructor.
         * @param disabled If <jk>true</jk>, get/put operations are no-ops.
+        * @param supplier The supplier for this cache.
         */
-       public TwoKeyConcurrentCache(boolean disabled) {
+       public TwoKeyConcurrentCache(boolean disabled, BiFunction<K1,K2,V> 
supplier) {
                this.disabled = disabled;
+               this.supplier = supplier;
        }
 
        /**
@@ -71,9 +75,14 @@ public class TwoKeyConcurrentCache<K1,K2,V> extends 
ConcurrentHashMap<TwoKeyConc
         */
        public V get(K1 key1, K2 key2) {
                if (disabled)
-                       return null;
+                       return (supplier == null ? null : supplier.apply(key1, 
key2));
                Key<K1,K2> key = new Key<>(key1, key2);
-               return super.get(key);
+               V v = super.get(key);
+               if (v == null && supplier != null) {
+                       v = supplier.apply(key1, key2);
+                       super.put(key, v);
+               }
+               return v;
        }
 
        static class Key<K1,K2> {
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 1c4a04f..b8aee9b 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
@@ -107,6 +107,8 @@ public final class ClassInfo {
         * @return The constructed class info, or <jk>null</jk> if the type was 
<jk>null</jk>.
         */
        public static ClassInfo of(Class<?> c, Type t) {
+               if (c == t)
+                       return of(c);
                return new ClassInfo(c, t);
        }
 
@@ -161,15 +163,18 @@ public final class ClassInfo {
        private final Type t;
        final Class<?> c;
        private final boolean isParameterizedType;
-       private Boolean isRepeatedAnnotation;
-       private ClassInfo[] interfaces, declaredInterfaces, parents, allParents;
-       private MethodInfo[] publicMethods, declaredMethods, allMethods, 
allMethodsParentFirst;
-       private MethodInfo repeatedAnnotationMethod;
-       private ConstructorInfo[] publicConstructors, declaredConstructors;
-       private FieldInfo[] publicFields, declaredFields, allFields;
+       private volatile Boolean isRepeatedAnnotation;
+       private volatile ClassInfo[] interfaces, declaredInterfaces, parents, 
allParents;
+       private volatile MethodInfo[] publicMethods, declaredMethods, 
allMethods, allMethodsParentFirst;
+       private volatile MethodInfo repeatedAnnotationMethod;
+       private volatile ConstructorInfo[] publicConstructors, 
declaredConstructors;
+       private volatile FieldInfo[] publicFields, declaredFields, allFields;
        private int dim = -1;
        private ClassInfo componentType;
 
+       private final ConcurrentHashMap<Method,MethodInfo> methods = new 
ConcurrentHashMap<>();
+       private final ConcurrentHashMap<Field,FieldInfo> fields = new 
ConcurrentHashMap<>();
+       private final ConcurrentHashMap<Constructor<?>,ConstructorInfo> 
constructors = new ConcurrentHashMap<>();
 
        /**
         * Constructor.
@@ -239,6 +244,33 @@ public final class ClassInfo {
                return null;
        }
 
+       MethodInfo getMethodInfo(Method x) {
+               MethodInfo i = methods.get(x);
+               if (i == null) {
+                       i = new MethodInfo(this, x);
+                       methods.put(x, i);
+               }
+               return i;
+       }
+
+       FieldInfo getFieldInfo(Field x) {
+               FieldInfo i = fields.get(x);
+               if (i == null) {
+                       i = new FieldInfo(this, x);
+                       fields.put(x, i);
+               }
+               return i;
+       }
+
+       ConstructorInfo getConstructorInfo(Constructor<?> x) {
+               ConstructorInfo i = constructors.get(x);
+               if (i == null) {
+                       i = new ConstructorInfo(this, x);
+                       constructors.put(x, i);
+               }
+               return i;
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Parent classes and interfaces.
        
//-----------------------------------------------------------------------------------------------------------------
@@ -330,7 +362,7 @@ public final class ClassInfo {
        }
 
        /** Results are in child-to-parent order. */
-       ClassInfo[] _getInterfaces() {
+       synchronized ClassInfo[] _getInterfaces() {
                if (interfaces == null) {
                        Set<ClassInfo> s = new LinkedHashSet<>();
                        for (ClassInfo ci : _getParents())
@@ -345,7 +377,7 @@ public final class ClassInfo {
        }
 
        /** Results are in the same order as Class.getInterfaces(). */
-       private ClassInfo[] _getDeclaredInterfaces() {
+       private synchronized ClassInfo[] _getDeclaredInterfaces() {
                if (declaredInterfaces == null) {
                        Class<?>[] ii = c == null ? new Class[0] : 
c.getInterfaces();
                        ClassInfo[] l = new ClassInfo[ii.length];
@@ -357,7 +389,7 @@ public final class ClassInfo {
        }
 
        /** Results are in child-to-parent order. */
-       ClassInfo[] _getParents() {
+       synchronized ClassInfo[] _getParents() {
                if (parents == null) {
                        List<ClassInfo> l = new ArrayList<>();
                        Class<?> pc = c;
@@ -371,7 +403,7 @@ public final class ClassInfo {
        }
 
        /** Results are classes-before-interfaces, then child-to-parent order. 
*/
-       private ClassInfo[] _getAllParents() {
+       private synchronized ClassInfo[] _getAllParents() {
                if (allParents == null) {
                        ClassInfo[] a1 = _getParents(), a2 = _getInterfaces();
                        ClassInfo[] l = new ClassInfo[a1.length + a2.length];
@@ -531,54 +563,62 @@ public final class ClassInfo {
                return this;
        }
 
-       private MethodInfo[] _getPublicMethods() {
+       private synchronized 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));
-                       l.sort(null);
-                       publicMethods = l.toArray(new MethodInfo[l.size()]);
+                       synchronized(this) {
+                               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(getMethodInfo(m));
+                               l.sort(null);
+                               publicMethods = l.toArray(new 
MethodInfo[l.size()]);
+                       }
                }
                return publicMethods;
        }
 
-       private MethodInfo[] _getDeclaredMethods() {
+       private synchronized 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));
-                       l.sort(null);
-                       declaredMethods = l.toArray(new MethodInfo[l.size()]);
+                       synchronized(this) {
+                               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(getMethodInfo(m));
+                               l.sort(null);
+                               declaredMethods = l.toArray(new 
MethodInfo[l.size()]);
+                       }
                }
                return declaredMethods;
        }
 
-       private MethodInfo[] _getAllMethods() {
+       private synchronized MethodInfo[] _getAllMethods() {
                if (allMethods == null) {
-                       List<MethodInfo> l = new ArrayList<>();
-                       for (ClassInfo c : _getAllParents())
-                               c._appendDeclaredMethods(l);
-                       allMethods = l.toArray(new MethodInfo[l.size()]);
+                       synchronized(this) {
+                               List<MethodInfo> l = new ArrayList<>();
+                               for (ClassInfo c : _getAllParents())
+                                       c._appendDeclaredMethods(l);
+                               allMethods = l.toArray(new 
MethodInfo[l.size()]);
+                       }
                }
                return allMethods;
        }
 
-       private MethodInfo[] _getAllMethodsParentFirst() {
+       private synchronized MethodInfo[] _getAllMethodsParentFirst() {
                if (allMethodsParentFirst == null) {
-                       List<MethodInfo> l = new ArrayList<>();
-                       ClassInfo[] parents = _getAllParents();
-                       for (int i = parents.length-1; i >=0; i--)
-                               parents[i]._appendDeclaredMethods(l);
-                       allMethodsParentFirst = l.toArray(new 
MethodInfo[l.size()]);
+                       synchronized(this) {
+                               List<MethodInfo> l = new ArrayList<>();
+                               ClassInfo[] parents = _getAllParents();
+                               for (int i = parents.length-1; i >=0; i--)
+                                       parents[i]._appendDeclaredMethods(l);
+                               allMethodsParentFirst = l.toArray(new 
MethodInfo[l.size()]);
+                       }
                }
                return allMethodsParentFirst;
        }
 
-       private List<MethodInfo> _appendDeclaredMethods(List<MethodInfo> l) {
+       private synchronized List<MethodInfo> 
_appendDeclaredMethods(List<MethodInfo> l) {
                for (MethodInfo mi : _getDeclaredMethods())
                        l.add(mi);
                return l;
@@ -660,26 +700,30 @@ public final class ClassInfo {
                return null;
        }
 
-       private ConstructorInfo[] _getPublicConstructors() {
+       private synchronized 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));
-                       l.sort(null);
-                       publicConstructors = l.toArray(new 
ConstructorInfo[l.size()]);
+                       synchronized(this) {
+                               Constructor<?>[] cc = c == null ? new 
Constructor[0] : c.getConstructors();
+                               List<ConstructorInfo> l = new 
ArrayList<>(cc.length);
+                               for (Constructor<?> ccc : cc)
+                                       l.add(getConstructorInfo(ccc));
+                               l.sort(null);
+                               publicConstructors = l.toArray(new 
ConstructorInfo[l.size()]);
+                       }
                }
                return publicConstructors;
        }
 
-       private ConstructorInfo[] _getDeclaredConstructors() {
+       private synchronized 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));
-                       l.sort(null);
-                       declaredConstructors = l.toArray(new 
ConstructorInfo[l.size()]);
+                       synchronized(this) {
+                               Constructor<?>[] cc = c == null ? new 
Constructor[0] : c.getDeclaredConstructors();
+                               List<ConstructorInfo> l = new 
ArrayList<>(cc.length);
+                               for (Constructor<?> ccc : cc)
+                                       l.add(getConstructorInfo(ccc));
+                               l.sort(null);
+                               declaredConstructors = l.toArray(new 
ConstructorInfo[l.size()]);
+                       }
                }
                return declaredConstructors;
        }
@@ -823,42 +867,48 @@ public final class ClassInfo {
 
        private FieldInfo[] _getPublicFields() {
                if (publicFields == null) {
-                       Map<String,FieldInfo> m = new LinkedHashMap<>();
-                       for (ClassInfo c : _getParents()) {
-                               for (FieldInfo f : c._getDeclaredFields()) {
-                                       String fn = f.getName();
-                                       if (f.isPublic() && ! 
(m.containsKey(fn) || "$jacocoData".equals(fn)))
-                                               m.put(f.getName(), f);
+                       synchronized(this) {
+                               Map<String,FieldInfo> m = new LinkedHashMap<>();
+                               for (ClassInfo c : _getParents()) {
+                                       for (FieldInfo f : 
c._getDeclaredFields()) {
+                                               String fn = f.getName();
+                                               if (f.isPublic() && ! 
(m.containsKey(fn) || "$jacocoData".equals(fn)))
+                                                       m.put(f.getName(), f);
+                                       }
                                }
+                               List<FieldInfo> l = new ArrayList<>(m.values());
+                               l.sort(null);
+                               publicFields = l.toArray(new 
FieldInfo[l.size()]);
                        }
-                       List<FieldInfo> l = new ArrayList<>(m.values());
-                       l.sort(null);
-                       publicFields = l.toArray(new FieldInfo[l.size()]);
                }
                return publicFields;
        }
 
-       private FieldInfo[] _getDeclaredFields() {
+       private synchronized 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 = l.toArray(new FieldInfo[l.size()]);
+                       synchronized(this) {
+                               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(getFieldInfo(f));
+                               l.sort(null);
+                               declaredFields = l.toArray(new 
FieldInfo[l.size()]);
+                       }
                }
                return declaredFields;
        }
 
-       private FieldInfo[] _getAllFields() {
+       private synchronized FieldInfo[] _getAllFields() {
                if (allFields == null) {
-                       List<FieldInfo> l = new ArrayList<>();
-                       ClassInfo[] parents = _getAllParents();
-                       for (int i = parents.length-1; i >=0; i--)
-                               for (FieldInfo f : 
parents[i]._getDeclaredFields())
-                                       l.add(f);
-                       allFields = l.toArray(new FieldInfo[l.size()]);
+                       synchronized(this) {
+                               List<FieldInfo> l = new ArrayList<>();
+                               ClassInfo[] parents = _getAllParents();
+                               for (int i = parents.length-1; i >=0; i--)
+                                       for (FieldInfo f : 
parents[i]._getDeclaredFields())
+                                               l.add(f);
+                               allFields = l.toArray(new FieldInfo[l.size()]);
+                       }
                }
                return allFields;
        }
@@ -2047,19 +2097,21 @@ public final class ClassInfo {
         */
        public boolean isRepeatedAnnotation() {
                if (isRepeatedAnnotation == null) {
-                       boolean b = false;
-                       MethodInfo mi = getPublicMethod(x -> 
x.hasName("value"));
-                       if (mi != null) {
-                               ClassInfo rt = mi.getReturnType();
-                               if (rt.isArray()) {
-                                       ClassInfo rct = rt.getComponentType();
-                                       if 
(rct.hasAnnotation(Repeatable.class)) {
-                                               Repeatable r = 
rct.getLastAnnotation(Repeatable.class);
-                                               b = r.value().equals(c);
+                       synchronized(this) {
+                               boolean b = false;
+                               repeatedAnnotationMethod = getPublicMethod(x -> 
x.hasName("value"));
+                               if (repeatedAnnotationMethod != null) {
+                                       ClassInfo rt = 
repeatedAnnotationMethod.getReturnType();
+                                       if (rt.isArray()) {
+                                               ClassInfo rct = 
rt.getComponentType();
+                                               if 
(rct.hasAnnotation(Repeatable.class)) {
+                                                       Repeatable r = 
rct.getLastAnnotation(Repeatable.class);
+                                                       b = r.value().equals(c);
+                                               }
                                        }
                                }
+                               isRepeatedAnnotation = b;
                        }
-                       isRepeatedAnnotation = b;
                }
                return isRepeatedAnnotation;
        }
@@ -2076,8 +2128,11 @@ public final class ClassInfo {
         */
        public MethodInfo getRepeatedAnnotationMethod() {
                if (isRepeatedAnnotation()) {
-                       if (repeatedAnnotationMethod == null)
-                               repeatedAnnotationMethod = getPublicMethod(x -> 
x.hasName("value"));
+                       if (repeatedAnnotationMethod == null) {
+                               synchronized(this) {
+                                       repeatedAnnotationMethod = 
getPublicMethod(x -> x.hasName("value"));
+                               }
+                       }
                        return repeatedAnnotationMethod;
                }
                return null;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
index 4558a2e..48757f2 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
@@ -29,24 +29,11 @@ import org.apache.juneau.internal.*;
 @FluentSetters
 public final class ConstructorInfo extends ExecutableInfo implements 
Comparable<ConstructorInfo> {
 
-       private final Constructor<?> c;
-
        
//-----------------------------------------------------------------------------------------------------------------
-       // Instantiation
+       // Static
        
//-----------------------------------------------------------------------------------------------------------------
 
        /**
-        * Constructor.
-        *
-        * @param declaringClass The class that declares this method.
-        * @param c The constructor being wrapped.
-        */
-       protected ConstructorInfo(ClassInfo declaringClass, Constructor<?> c) {
-               super(declaringClass, c);
-               this.c = c;
-       }
-
-       /**
         * Convenience method for instantiating a {@link ConstructorInfo};
         *
         * @param declaringClass The class that declares this method.
@@ -56,7 +43,7 @@ public final class ConstructorInfo extends ExecutableInfo 
implements Comparable<
        public static ConstructorInfo of(ClassInfo declaringClass, 
Constructor<?> c) {
                if (c == null)
                        return null;
-               return new ConstructorInfo(declaringClass, c);
+               return ClassInfo.of(declaringClass).getConstructorInfo(c);
        }
 
        /**
@@ -68,7 +55,24 @@ public final class ConstructorInfo extends ExecutableInfo 
implements Comparable<
        public static ConstructorInfo of(Constructor<?> c) {
                if (c == null)
                        return null;
-               return new ConstructorInfo(ClassInfo.of(c.getDeclaringClass()), 
c);
+               return 
ClassInfo.of(c.getDeclaringClass()).getConstructorInfo(c);
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Instance
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       private final Constructor<?> c;
+
+       /**
+        * Constructor.
+        *
+        * @param declaringClass The class that declares this method.
+        * @param c The constructor being wrapped.
+        */
+       protected ConstructorInfo(ClassInfo declaringClass, Constructor<?> c) {
+               super(declaringClass, c);
+               this.c = c;
        }
 
        /**
@@ -81,7 +85,6 @@ public final class ConstructorInfo extends ExecutableInfo 
implements Comparable<
                return (Constructor<T>)c;
        }
 
-
        
//-----------------------------------------------------------------------------------------------------------------
        // Annotations
        
//-----------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
index 0843196..f7092f4 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
@@ -36,11 +36,11 @@ public abstract class ExecutableInfo {
        final Executable e;
        final boolean isConstructor;
 
-       private ParamInfo[] params;
-       private ClassInfo[] paramTypes, exceptionInfos;
-       private Class<?>[] rawParamTypes;
-       private Type[] rawGenericParamTypes;
-       private Parameter[] rawParameters;
+       private volatile ParamInfo[] params;
+       private volatile ClassInfo[] paramTypes, exceptionInfos;
+       private volatile Class<?>[] rawParamTypes;
+       private volatile Type[] rawGenericParamTypes;
+       private volatile Parameter[] rawParameters;
 
        /**
         * Constructor.
@@ -234,57 +234,70 @@ public abstract class ExecutableInfo {
 
        private ParamInfo[] _getParams() {
                if (params == null) {
-                       Parameter[] rp = _getRawParameters();
-                       ParamInfo[] l = new ParamInfo[rp.length];
-                       for (int i = 0; i < rp.length; i++)
-                               l[i] = new ParamInfo(this, rp[i], i);
-                       params = l;
+                       synchronized(this) {
+                               Parameter[] rp = _getRawParameters();
+                               ParamInfo[] l = new ParamInfo[rp.length];
+                               for (int i = 0; i < rp.length; i++)
+                                       l[i] = new ParamInfo(this, rp[i], i);
+                               params = l;
+                       }
                }
                return params;
        }
 
        ClassInfo[] _getParamTypes() {
                if (paramTypes == null) {
-                       Class<?>[] ptc = _getRawParamTypes();
-                       // Note that due to a bug involving Enum constructors, 
getGenericParameterTypes() may
-                       // always return an empty array.  This appears to be 
fixed in Java 8 b75.
-                       Type[] ptt = _getRawGenericParamTypes();
-                       if (ptt.length != ptc.length) {
-                               // Bug in javac: generic type array excludes 
enclosing instance parameter
-                               // for inner classes with at least one generic 
constructor parameter.
-                               if (ptt.length + 1 == ptc.length) {
-                                       Type[] ptt2 = new Type[ptc.length];
-                                       ptt2[0] = ptc[0];
-                                       for (int i = 0; i < ptt.length; i++)
-                                               ptt2[i+1] = ptt[i];
-                                       ptt = ptt2;
-                               } else {
-                                       ptt = ptc;
+                       synchronized(this) {
+                               Class<?>[] ptc = _getRawParamTypes();
+                               // Note that due to a bug involving Enum 
constructors, getGenericParameterTypes() may
+                               // always return an empty array.  This appears 
to be fixed in Java 8 b75.
+                               Type[] ptt = _getRawGenericParamTypes();
+                               if (ptt.length != ptc.length) {
+                                       // Bug in javac: generic type array 
excludes enclosing instance parameter
+                                       // for inner classes with at least one 
generic constructor parameter.
+                                       if (ptt.length + 1 == ptc.length) {
+                                               Type[] ptt2 = new 
Type[ptc.length];
+                                               ptt2[0] = ptc[0];
+                                               for (int i = 0; i < ptt.length; 
i++)
+                                                       ptt2[i+1] = ptt[i];
+                                               ptt = ptt2;
+                                       } else {
+                                               ptt = ptc;
+                                       }
                                }
+                               ClassInfo[] l = new ClassInfo[ptc.length];
+                               for (int i = 0; i < ptc.length; i++)
+                                       l[i] = ClassInfo.of(ptc[i], ptt[i]);
+                               paramTypes = l;
                        }
-                       ClassInfo[] l = new ClassInfo[ptc.length];
-                       for (int i = 0; i < ptc.length; i++)
-                               l[i] = ClassInfo.of(ptc[i], ptt[i]);
-                       paramTypes = l;
                }
                return paramTypes;
        }
 
        Class<?>[] _getRawParamTypes() {
-               if (rawParamTypes == null)
-                       rawParamTypes = e.getParameterTypes();
+               if (rawParamTypes == null) {
+                       synchronized(this) {
+                               rawParamTypes = e.getParameterTypes();
+                       }
+               }
                return rawParamTypes;
        }
 
        private Type[] _getRawGenericParamTypes() {
-               if (rawGenericParamTypes == null)
-                       rawGenericParamTypes = e.getGenericParameterTypes();
+               if (rawGenericParamTypes == null) {
+                       synchronized(this) {
+                               rawGenericParamTypes = 
e.getGenericParameterTypes();
+                       }
+               }
                return rawGenericParamTypes;
        }
 
        private Parameter[] _getRawParameters() {
-               if (rawParameters == null)
-                       rawParameters = e.getParameters();
+               if (rawParameters == null) {
+                       synchronized(this) {
+                               rawParameters = e.getParameters();
+                       }
+               }
                return rawParameters;
        }
 
@@ -347,11 +360,13 @@ public abstract class ExecutableInfo {
 
        private ClassInfo[] _getExceptionTypes() {
                if (exceptionInfos == null) {
-                       Class<?>[] exceptionTypes = e.getExceptionTypes();
-                       ClassInfo[] l = new ClassInfo[exceptionTypes.length];
-                       for (int i = 0; i < exceptionTypes.length; i++)
-                               l[i] = ClassInfo.of(exceptionTypes[i]);
-                       exceptionInfos = l;
+                       synchronized(this) {
+                               Class<?>[] exceptionTypes = 
e.getExceptionTypes();
+                               ClassInfo[] l = new 
ClassInfo[exceptionTypes.length];
+                               for (int i = 0; i < exceptionTypes.length; i++)
+                                       l[i] = ClassInfo.of(exceptionTypes[i]);
+                               exceptionInfos = l;
+                       }
                }
                return exceptionInfos;
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/FieldInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/FieldInfo.java
index f789423..5a10114 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/FieldInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/FieldInfo.java
@@ -29,25 +29,11 @@ import org.apache.juneau.*;
  */
 public final class FieldInfo implements Comparable<FieldInfo> {
 
-       private final Field f;
-       private ClassInfo declaringClass, type;
-
        
//-----------------------------------------------------------------------------------------------------------------
-       // Instantiation
+       // Static
        
//-----------------------------------------------------------------------------------------------------------------
 
        /**
-        * Constructor.
-        *
-        * @param declaringClass The class that declares this method.
-        * @param f The field being wrapped.
-        */
-       protected FieldInfo(ClassInfo declaringClass, Field f) {
-               this.declaringClass = declaringClass;
-               this.f = f;
-       }
-
-       /**
         * Convenience method for instantiating a {@link FieldInfo};
         *
         * @param declaringClass The class that declares this method.
@@ -57,7 +43,7 @@ public final class FieldInfo implements Comparable<FieldInfo> 
{
        public static FieldInfo of(ClassInfo declaringClass, Field f) {
                if (f == null)
                        return null;
-               return new FieldInfo(declaringClass, f);
+               return ClassInfo.of(declaringClass).getFieldInfo(f);
        }
 
        /**
@@ -69,7 +55,26 @@ public final class FieldInfo implements 
Comparable<FieldInfo> {
        public static FieldInfo of(Field f) {
                if (f == null)
                        return null;
-               return new FieldInfo(ClassInfo.of(f.getDeclaringClass()), f);
+               return ClassInfo.of(f.getDeclaringClass()).getFieldInfo(f);
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Instance
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       private final Field f;
+       private final ClassInfo declaringClass;
+       private volatile ClassInfo type;
+
+       /**
+        * Constructor.
+        *
+        * @param declaringClass The class that declares this method.
+        * @param f The field being wrapped.
+        */
+       protected FieldInfo(ClassInfo declaringClass, Field f) {
+               this.declaringClass = declaringClass;
+               this.f = f;
        }
 
        /**
@@ -87,8 +92,6 @@ public final class FieldInfo implements Comparable<FieldInfo> 
{
         * @return Metadata about the declaring class.
         */
        public ClassInfo getDeclaringClass() {
-               if (declaringClass == null)
-                       declaringClass = ClassInfo.of(f.getDeclaringClass());
                return declaringClass;
        }
 
@@ -425,8 +428,11 @@ public final class FieldInfo implements 
Comparable<FieldInfo> {
         * @return The type of this field.
         */
        public ClassInfo getType() {
-               if (type == null)
-                       type = ClassInfo.of(f.getType());
+               if (type == null) {
+                       synchronized(this) {
+                               type = ClassInfo.of(f.getType());
+                       }
+               }
                return type;
        }
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
index 33dc392..d3b8295 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
@@ -32,26 +32,11 @@ import org.apache.juneau.internal.*;
 @FluentSetters
 public final class MethodInfo extends ExecutableInfo implements 
Comparable<MethodInfo> {
 
-       private ClassInfo returnType;
-       private final Method m;
-       private Method[] matching;
-
        
//-----------------------------------------------------------------------------------------------------------------
-       // Instantiation
+       // Static
        
//-----------------------------------------------------------------------------------------------------------------
 
        /**
-        * Constructor.
-        *
-        * @param declaringClass The class that declares this method.
-        * @param m The method being wrapped.
-        */
-       protected MethodInfo(ClassInfo declaringClass, Method m) {
-               super(declaringClass, m);
-               this.m = m;
-       }
-
-       /**
         * Convenience method for instantiating a {@link MethodInfo};
         *
         * @param declaringClass The class that declares this method.
@@ -61,7 +46,7 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
        public static MethodInfo of(ClassInfo declaringClass, Method m) {
                if (m == null)
                        return null;
-               return new MethodInfo(declaringClass, m);
+               return declaringClass.getMethodInfo(m);
        }
 
        /**
@@ -74,7 +59,7 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
        public static MethodInfo of(Class<?> declaringClass, Method m) {
                if (m == null)
                        return null;
-               return new MethodInfo(ClassInfo.of(declaringClass), m);
+               return ClassInfo.of(declaringClass).getMethodInfo(m);
        }
 
        /**
@@ -86,7 +71,26 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
        public static MethodInfo of(Method m) {
                if (m == null)
                        return null;
-               return new MethodInfo(ClassInfo.of(m.getDeclaringClass()), m);
+               return ClassInfo.of(m.getDeclaringClass()).getMethodInfo(m);
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Instance
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       private final Method m;
+       private volatile ClassInfo returnType;
+       private volatile Method[] matching;
+
+       /**
+        * Constructor.
+        *
+        * @param declaringClass The class that declares this method.
+        * @param m The method being wrapped.
+        */
+       protected MethodInfo(ClassInfo declaringClass, Method m) {
+               super(declaringClass, m);
+               this.m = m;
        }
 
        /**
@@ -181,8 +185,10 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
 
        private Method[] _getMatching() {
                if (matching == null) {
-                       List<Method> l = findMatching(new ArrayList<>(), m, 
m.getDeclaringClass());
-                       matching = l.toArray(new Method[l.size()]);
+                       synchronized(this) {
+                               List<Method> l = findMatching(new 
ArrayList<>(), m, m.getDeclaringClass());
+                               matching = l.toArray(new Method[l.size()]);
+                       }
                }
                return matching;
        }
@@ -503,8 +509,11 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
         * @return The generic return type of this method.
         */
        public ClassInfo getReturnType() {
-               if (returnType == null)
-                       returnType = ClassInfo.of(m.getReturnType(), 
m.getGenericReturnType());
+               if (returnType == null) {
+                       synchronized(this) {
+                               returnType = ClassInfo.of(m.getReturnType(), 
m.getGenericReturnType());
+                       }
+               }
                return returnType;
        }
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
index edb92c2..ce35889 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
@@ -20,8 +20,6 @@ import static org.apache.juneau.internal.StringUtils.*;
 import java.lang.reflect.*;
 import java.util.*;
 
-import org.apache.juneau.collections.*;
-
 /**
  * Allows arbitrary objects to be mapped to classes and methods base on 
class/method name keys.
  *
@@ -250,11 +248,10 @@ public class ReflectionMap<V> {
        // Instance
        
//-----------------------------------------------------------------------------------------------------------------
 
-       private final List<ClassEntry<V>> classEntries;
-       private final List<MethodEntry<V>> methodEntries;
-       private final List<FieldEntry<V>> fieldEntries;
-       private final List<ConstructorEntry<V>> constructorEntries;
-       final boolean noClassEntries, noMethodEntries, noFieldEntries, 
noConstructorEntries;
+       final ClassEntry<V>[] classEntries;
+       final MethodEntry<V>[] methodEntries;
+       final FieldEntry<V>[] fieldEntries;
+       final ConstructorEntry<V>[] constructorEntries;
 
        /**
         * Constructor.
@@ -262,14 +259,10 @@ public class ReflectionMap<V> {
         * @param b Initializer object.
         */
        protected ReflectionMap(Builder<V> b) {
-               this.classEntries = Collections.unmodifiableList(new 
ArrayList<>(b.classEntries));
-               this.methodEntries = Collections.unmodifiableList(new 
ArrayList<>(b.methodEntries));
-               this.fieldEntries = Collections.unmodifiableList(new 
ArrayList<>(b.fieldEntries));
-               this.constructorEntries = Collections.unmodifiableList(new 
ArrayList<>(b.constructorEntries));
-               this.noClassEntries = classEntries.isEmpty();
-               this.noMethodEntries = methodEntries.isEmpty();
-               this.noFieldEntries = fieldEntries.isEmpty();
-               this.noConstructorEntries = constructorEntries.isEmpty();
+               this.classEntries = b.classEntries.toArray(new 
ClassEntry[b.classEntries.size()]);
+               this.methodEntries = b.methodEntries.toArray(new 
MethodEntry[b.methodEntries.size()]);
+               this.fieldEntries = b.fieldEntries.toArray(new 
FieldEntry[b.fieldEntries.size()]);
+               this.constructorEntries = b.constructorEntries.toArray(new 
ConstructorEntry[b.constructorEntries.size()]);
        }
 
        static List<String> splitNames(String key) {
@@ -303,11 +296,10 @@ public class ReflectionMap<V> {
         * @return The matching object.  Never <jk>null</jk>.
         */
        public Optional<V> find(Class<?> c, Class<? extends V> ofType) {
-               if (! noClassEntries)
-                       for (ClassEntry<V> e : classEntries)
-                               if (e.matches(c))
-                                       if (ofType == null || 
ofType.isInstance(e.value))
-                                               return 
Optional.ofNullable(e.value);
+               for (ClassEntry<V> e : classEntries)
+                       if (e.matches(c))
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       return Optional.ofNullable(e.value);
                return Optional.empty();
        }
 
@@ -329,7 +321,12 @@ public class ReflectionMap<V> {
         * @return A modifiable list of matching values.  Never <jk>null</jk>.
         */
        public List<V> findAll(Class<?> c, Class<? extends V> ofType) {
-               return appendAll(c, ofType, null);
+               List<V> list = null;
+               for (ClassEntry<V> e : classEntries)
+                       if (e.matches(c) && e.value != null)
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       list = lazyAdd(list, e.value);
+               return lazyList(list);
        }
 
        /**
@@ -339,7 +336,11 @@ public class ReflectionMap<V> {
         * @return A modifiable list of matching values.  Never <jk>null</jk>.
         */
        public List<V> findAll(Class<?> c) {
-               return appendAll(c, null, null);
+               List<V> list = null;
+               for (ClassEntry<V> e : classEntries)
+                       if (e.matches(c) && e.value != null)
+                               list = lazyAdd(list, e.value);
+               return lazyList(list);
        }
 
        /**
@@ -347,18 +348,23 @@ public class ReflectionMap<V> {
         *
         * @param c The class to test for.
         * @param ofType Only return objects of the specified type.
-        * @param l The list to append values to.  Can be <jk>null</jk>.
+        * @param array The array to append values to.
         * @return The same list passed in or a new modifiable list if 
<jk>null</jk>.
         */
-       public List<V> appendAll(Class<?> c, Class<? extends V> ofType, List<V> 
l) {
-               if (l == null)
-                       l = AList.create();
-               if (! noClassEntries)
-                       for (ClassEntry<V> e : classEntries)
-                               if (e.matches(c) && e.value != null)
-                                       if (ofType == null || 
ofType.isInstance(e.value))
-                                               l.add(e.value);
-               return l;
+       public V[] appendAll(Class<?> c, Class<? extends V> ofType, V[] array) {
+               List<V> list = null;
+               for (ClassEntry<V> e : classEntries)
+                       if (e.matches(c) && e.value != null)
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       list = lazyAdd(array, list, e.value);
+               return lazyArray(array, list);
+       }
+
+       private static <V> List<V> lazyAdd(List<V> list, V v) {
+               if (list == null)
+                       list = new ArrayList<>();
+               list.add(v);
+               return list;
        }
 
        /**
@@ -369,11 +375,10 @@ public class ReflectionMap<V> {
         * @return The matching object.  Never <jk>null</jk>.
         */
        public Optional<V> find(Method m, Class<? extends V> ofType) {
-               if (! noMethodEntries)
-                       for (MethodEntry<V> e : methodEntries)
-                               if (e.matches(m))
-                                       if (ofType == null || 
ofType.isInstance(e.value))
-                                               return 
Optional.ofNullable(e.value);
+               for (MethodEntry<V> e : methodEntries)
+                       if (e.matches(m))
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       return Optional.ofNullable(e.value);
                return Optional.empty();
        }
 
@@ -395,7 +400,12 @@ public class ReflectionMap<V> {
         * @return A modifiable list of matching values.  Never <jk>null</jk>.
         */
        public List<V> findAll(Method m, Class<? extends V> ofType) {
-               return appendAll(m, ofType, null);
+               List<V> list = null;
+               for (MethodEntry<V> e : methodEntries)
+                       if (e.matches(m) && e.value != null)
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       list = lazyAdd(list, e.value);
+               return lazyList(list);
        }
 
        /**
@@ -405,7 +415,11 @@ public class ReflectionMap<V> {
         * @return A modifiable list of matching values.  Never <jk>null</jk>.
         */
        public List<V> findAll(Method m) {
-               return appendAll(m, null, null);
+               List<V> list = null;
+               for (MethodEntry<V> e : methodEntries)
+                       if (e.matches(m) && e.value != null)
+                               list = lazyAdd(list, e.value);
+               return lazyList(list);
        }
 
        /**
@@ -413,18 +427,16 @@ public class ReflectionMap<V> {
         *
         * @param m The method to test for.
         * @param ofType Only return objects of the specified type.
-        * @param l The list to append values to.  Can be <jk>null</jk>.
+        * @param array The array to append values to.
         * @return The same list passed in or a new modifiable list if 
<jk>null</jk>.
         */
-       public List<V> appendAll(Method m, Class<? extends V> ofType, List<V> 
l) {
-               if (l == null)
-                       l = AList.create();
-               if (! noMethodEntries)
-                       for (MethodEntry<V> e : methodEntries)
-                               if (e.matches(m) && e.value != null)
-                                       if (ofType == null || 
ofType.isInstance(e.value))
-                                               l.add(e.value);
-               return l;
+       public V[] appendAll(Method m, Class<? extends V> ofType, V[] array) {
+               List<V> list = null;
+               for (MethodEntry<V> e : methodEntries)
+                       if (e.matches(m) && e.value != null)
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       list = lazyAdd(array, list, e.value);
+               return lazyArray(array, list);
        }
 
        /**
@@ -435,11 +447,10 @@ public class ReflectionMap<V> {
         * @return The matching object.  Never <jk>null</jk>.
         */
        public Optional<V> find(Field f, Class<? extends V> ofType) {
-               if (! noFieldEntries)
-                       for (FieldEntry<V> e : fieldEntries)
-                               if (e.matches(f))
-                                       if (ofType == null || 
ofType.isInstance(e.value))
-                                               return 
Optional.ofNullable(e.value);
+               for (FieldEntry<V> e : fieldEntries)
+                       if (e.matches(f))
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       return Optional.ofNullable(e.value);
                return Optional.empty();
        }
 
@@ -461,7 +472,12 @@ public class ReflectionMap<V> {
         * @return A modifiable list of matching values.  Never <jk>null</jk>.
         */
        public List<V> findAll(Field f, Class<? extends V> ofType) {
-               return appendAll(f, ofType, null);
+               List<V> list = null;
+               for (FieldEntry<V> e : fieldEntries)
+                       if (e.matches(f) && e.value != null)
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       list = lazyAdd(list, e.value);
+               return lazyList(list);
        }
 
        /**
@@ -471,7 +487,11 @@ public class ReflectionMap<V> {
         * @return A modifiable list of matching values.  Never <jk>null</jk>.
         */
        public List<V> findAll(Field f) {
-               return appendAll(f, null, null);
+               List<V> list = null;
+               for (FieldEntry<V> e : fieldEntries)
+                       if (e.matches(f) && e.value != null)
+                               list = lazyAdd(list, e.value);
+               return lazyList(list);
        }
 
        /**
@@ -479,18 +499,16 @@ public class ReflectionMap<V> {
         *
         * @param f The field to test for.
         * @param ofType Only return objects of the specified type.
-        * @param l The list to append values to.  Can be <jk>null</jk>.
+        * @param array The array to append values to.
         * @return The same list passed in or a new modifiable list if 
<jk>null</jk>.
         */
-       public List<V> appendAll(Field f, Class<? extends V> ofType, List<V> l) 
{
-               if (l == null)
-                       l = AList.create();
-               if (! noFieldEntries)
-                       for (FieldEntry<V> e : fieldEntries)
-                               if (e.matches(f) && e.value != null)
-                                       if (ofType == null || 
ofType.isInstance(e.value))
-                                               l.add(e.value);
-               return l == null ? new ArrayList<>(0) : l;
+       public V[] appendAll(Field f, Class<? extends V> ofType, V[] array) {
+               List<V> list = null;
+               for (FieldEntry<V> e : fieldEntries)
+                       if (e.matches(f) && e.value != null)
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       list = lazyAdd(array, list, e.value);
+               return lazyArray(array, list);
        }
 
        /**
@@ -501,11 +519,10 @@ public class ReflectionMap<V> {
         * @return The matching object.  Never <jk>null</jk>.
         */
        public Optional<V> find(Constructor<?> c, Class<? extends V> ofType) {
-               if (! noConstructorEntries)
-                       for (ConstructorEntry<V> e : constructorEntries)
-                               if (e.matches(c))
-                                       if (ofType == null || 
ofType.isInstance(e.value))
-                                               return 
Optional.ofNullable(e.value);
+               for (ConstructorEntry<V> e : constructorEntries)
+                       if (e.matches(c))
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       return Optional.ofNullable(e.value);
                return Optional.empty();
        }
 
@@ -527,7 +544,12 @@ public class ReflectionMap<V> {
         * @return A modifiable list of matching values.  Never <jk>null</jk>.
         */
        public List<V> findAll(Constructor<?> c, Class<? extends V> ofType) {
-               return appendAll(c, ofType, null);
+               List<V> list = null;
+               for (ConstructorEntry<V> e : constructorEntries)
+                       if (e.matches(c) && e.value != null)
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       list = lazyAdd(list, e.value);
+               return lazyList(list);
        }
 
        /**
@@ -537,7 +559,11 @@ public class ReflectionMap<V> {
         * @return A modifiable list of matching values.  Never <jk>null</jk>.
         */
        public List<V> findAll(Constructor<?> c) {
-               return appendAll(c, null, null);
+               List<V> list = null;
+               for (ConstructorEntry<V> e : constructorEntries)
+                       if (e.matches(c) && e.value != null)
+                               list = lazyAdd(list, e.value);
+               return lazyList(list);
        }
 
        /**
@@ -545,18 +571,16 @@ public class ReflectionMap<V> {
         *
         * @param c The constructor to test for.
         * @param ofType Only return objects of the specified type.
-        * @param l The list to append values to.  Can be <jk>null</jk>.
+        * @param array The array to append values to.
         * @return The same list passed in or a new modifiable list if 
<jk>null</jk>.
         */
-       public List<V> appendAll(Constructor<?> c, Class<? extends V> ofType, 
List<V> l) {
-               if (l == null)
-                       l = AList.create();
-               if (! noConstructorEntries)
-                       for (ConstructorEntry<V> e : constructorEntries)
-                               if (e.matches(c) && e.value != null)
-                                       if (ofType == null || 
ofType.isInstance(e.value))
-                                               l.add(e.value);
-               return l;
+       public V[] appendAll(Constructor<?> c, Class<? extends V> ofType, V[] 
array) {
+               List<V> list = null;
+               for (ConstructorEntry<V> e : constructorEntries)
+                       if (e.matches(c) && e.value != null)
+                               if (ofType == null || 
ofType.isInstance(e.value))
+                                       list = lazyAdd(array, list, e.value);
+               return lazyArray(array, list);
        }
 
        static class ClassEntry<V> {
@@ -769,4 +793,28 @@ public class ReflectionMap<V> {
                        .a("constructorEntries", constructorEntries)
                        .asString();
        }
+       
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Utility methods
+       
//-----------------------------------------------------------------------------------------------------------------
+       
+       private static <V> List<V> lazyList(List<V> list) {
+               return list == null ? Collections.emptyList() : list;
+       }
+
+       private static <V> List<V> lazyAdd(V[] array, List<V> list, V v) {
+               if (list == null)
+                       list = new ArrayList<>(Arrays.asList(array));
+               list.add(v);
+               return list;
+       }
+
+       @SuppressWarnings("unchecked")
+       private static <V> V[] lazyArray(V[] array, List<V> list) {
+               if (list == null)
+                       return array;
+               array = 
(V[])Array.newInstance(array.getClass().getComponentType(), list.size());
+               list.toArray(array);
+               return array;
+       }
 }
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/utils/ReflectionMapTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/utils/ReflectionMapTest.java
index a6b23fe..ce2315d 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/utils/ReflectionMapTest.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/utils/ReflectionMapTest.java
@@ -28,10 +28,10 @@ public class ReflectionMapTest {
        }
 
        private void checkEntries(ReflectionMap<?> m, boolean hasClass, boolean 
hasMethods, boolean hasFields, boolean hasConstructors) {
-               assertEquals(m.noClassEntries, ! hasClass);
-               assertEquals(m.noMethodEntries, ! hasMethods);
-               assertEquals(m.noFieldEntries, ! hasFields);
-               assertEquals(m.noConstructorEntries, ! hasConstructors);
+               assertEquals(m.classEntries.length == 0, ! hasClass);
+               assertEquals(m.methodEntries.length == 0, ! hasMethods);
+               assertEquals(m.fieldEntries.length == 0, ! hasFields);
+               assertEquals(m.constructorEntries.length == 0, ! 
hasConstructors);
        }
 
        
//------------------------------------------------------------------------------------------------------------------

Reply via email to