4040import java .net .MalformedURLException ;
4141import java .net .URL ;
4242import java .util .ArrayList ;
43+ import java .util .HashMap ;
4344import java .util .List ;
45+ import java .util .Map ;
4446
4547/**
4648 * Useful methods for working with {@link Class} objects and primitive types.
@@ -53,6 +55,18 @@ private ClassUtils() {
5355 // prevent instantiation of utility class
5456 }
5557
58+ /**
59+ * This maps a base class (key1) to a map of annotation classes (key2), which
60+ * then maps to a list of {@link Field} instances, being the set of fields in
61+ * the base class with the specified annotation.
62+ * <p>
63+ * This map serves as a cache, as these annotations should not change at
64+ * runtime and thus can alleviate the frequency field querying.
65+ * </p>
66+ */
67+ private static final Map <Class <?>, Map <Class <?>, List <Field >>> fields =
68+ new HashMap <Class <?>, Map <Class <?>, List <Field >>>();
69+
5670 // -- Class loading, querying and reflection --
5771
5872 /**
@@ -347,8 +361,12 @@ public static <A extends Annotation> List<Method> getAnnotatedMethods(
347361 public static <A extends Annotation > List <Field > getAnnotatedFields (
348362 final Class <?> c , final Class <A > annotationClass )
349363 {
350- final ArrayList <Field > fields = new ArrayList <Field >();
364+ List <Field > fields = lookupFields (c , annotationClass );
365+
366+ if (fields != null ) return fields ;
367+ fields = new ArrayList <Field >();
351368 getAnnotatedFields (c , annotationClass , fields );
369+
352370 return fields ;
353371 }
354372
@@ -383,6 +401,8 @@ public static <A extends Annotation> void getAnnotatedFields(
383401 final A ann = f .getAnnotation (annotationClass );
384402 if (ann != null ) fields .add (f );
385403 }
404+
405+ mapFields (c , annotationClass , fields );
386406 }
387407
388408 /**
@@ -518,6 +538,45 @@ public static int compare(final Class<?> c1, final Class<?> c2) {
518538 return MiscUtils .compare (name1 , name2 );
519539 }
520540
541+ // -- Helper methods --
542+
543+ /**
544+ * Populates the provided list with {@link Field} entries of the given base
545+ * class which are annotated with the specified annotation type.
546+ *
547+ * @param c Base class
548+ * @param annotationClass Annotation type
549+ * @param annotatedFields Field list to populate
550+ */
551+ private static <A extends Annotation > void mapFields (Class <?> c ,
552+ Class <A > annotationClass , List <Field > annotatedFields )
553+ {
554+ Map <Class <?>, List <Field >> map = fields .get (c );
555+ if (map == null ) {
556+ map = new HashMap <Class <?>, List <Field >>();
557+ fields .put (c , map );
558+ }
559+
560+ map .put (annotationClass , annotatedFields );
561+ }
562+
563+ /**
564+ * @param c Base class
565+ * @param annotationClass Annotation type
566+ * @return Cached list of Fields in the base class with the specified
567+ * annotation, or null if a cached list does not exist.
568+ */
569+ private static <A extends Annotation > List <Field > lookupFields (
570+ final Class <?> c , final Class <A > annotationClass )
571+ {
572+ List <Field > annotatedFields = null ;
573+ Map <Class <?>, List <Field >> annotationTypes = fields .get (c );
574+ if (annotationTypes != null ) {
575+ annotatedFields = annotationTypes .get (annotationClass );
576+ }
577+ return annotatedFields ;
578+ }
579+
521580 // -- Deprecated methods --
522581
523582 /** @deprecated use {@link ConversionUtils#convert(Object, Class)} */
0 commit comments