Skip to content

Commit 6ef0392

Browse files
committed
Cache Methods by annotation, class
For context injection we frequently need to find all Methods in a class with a given annotation. There is no reason to expect this information will change at runtime so we should cache these sets to improve the performance of injection.
1 parent 7ae4103 commit 6ef0392

File tree

1 file changed

+57
-2
lines changed

1 file changed

+57
-2
lines changed

src/main/java/org/scijava/util/ClassUtils.java

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ private ClassUtils() {
6767
private static final Map<Class<?>, Map<Class<?>, List<Field>>> fields =
6868
new HashMap<Class<?>, Map<Class<?>, List<Field>>>();
6969

70+
/**
71+
* This maps a base class (key1) to a map of annotation classes (key2), which
72+
* then maps to a list of {@link Method} instances, being the set of methods
73+
* in the base class with the specified annotation.
74+
* <p>
75+
* This map serves as a cache, as these annotations should not change at
76+
* runtime and thus can alleviate the frequency of method querying.
77+
* </p>
78+
*/
79+
private static final Map<Class<?>, Map<Class<?>, List<Method>>> methods =
80+
new HashMap<Class<?>, Map<Class<?>, List<Method>>>();
81+
7082
// -- Class loading, querying and reflection --
7183

7284
/**
@@ -300,8 +312,13 @@ public static URL getLocation(final Class<?> c) {
300312
public static <A extends Annotation> List<Method> getAnnotatedMethods(
301313
final Class<?> c, final Class<A> annotationClass)
302314
{
303-
final ArrayList<Method> methods = new ArrayList<Method>();
304-
getAnnotatedMethods(c, annotationClass, methods);
315+
List<Method> methods = lookupMethods(c, annotationClass);
316+
317+
if (methods == null) {
318+
methods = new ArrayList<Method>();
319+
getAnnotatedMethods(c, annotationClass, methods);
320+
}
321+
305322
return methods;
306323
}
307324

@@ -344,6 +361,8 @@ public static <A extends Annotation> List<Method> getAnnotatedMethods(
344361
final A ann = m.getAnnotation(annotationClass);
345362
if (ann != null) methods.add(m);
346363
}
364+
365+
mapMethods(c, annotationClass, methods);
347366
}
348367

349368
/**
@@ -560,6 +579,26 @@ private static <A extends Annotation> void mapFields(Class<?> c,
560579
map.put(annotationClass, annotatedFields);
561580
}
562581

582+
/**
583+
* Populates the provided list with {@link Method} entries of the given base
584+
* class which are annotated with the specified annotation type.
585+
*
586+
* @param c Base class
587+
* @param annotationClass Annotation type
588+
* @param annotatedFields Method list to populate
589+
*/
590+
private static <A extends Annotation> void mapMethods(final Class<?> c,
591+
final Class<A> annotationClass, List<Method> annotatedMethods)
592+
{
593+
Map<Class<?>, List<Method>> map = methods.get(c);
594+
if (map == null) {
595+
map = new HashMap<Class<?>, List<Method>>();
596+
methods.put(c, map);
597+
}
598+
599+
map.put(annotationClass, annotatedMethods);
600+
}
601+
563602
/**
564603
* @param c Base class
565604
* @param annotationClass Annotation type
@@ -577,6 +616,22 @@ private static <A extends Annotation> List<Field> lookupFields(
577616
return annotatedFields;
578617
}
579618

619+
/**
620+
* @param c Base class
621+
* @param annotationClass Annotation type
622+
* @return Cached list of Methods in the base class with the specified
623+
* annotation, or null if a cached list does not exist.
624+
*/
625+
private static <A extends Annotation> List<Method> lookupMethods(
626+
final Class<?> c, final Class<A> annotationClass)
627+
{
628+
List<Method> annotatedFields = null;
629+
Map<Class<?>, List<Method>> annotationTypes = methods.get(c);
630+
if (annotationTypes != null) {
631+
annotatedFields = annotationTypes.get(annotationClass);
632+
}
633+
return annotatedFields;
634+
}
580635
// -- Deprecated methods --
581636

582637
/** @deprecated use {@link ConversionUtils#convert(Object, Class)} */

0 commit comments

Comments
 (0)