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);
}
//------------------------------------------------------------------------------------------------------------------