26
26
import java .util .List ;
27
27
import java .util .Map ;
28
28
import java .util .Set ;
29
- import java .util .WeakHashMap ;
30
29
31
30
import org .apache .commons .logging .Log ;
32
31
import org .apache .commons .logging .LogFactory ;
33
32
34
33
import org .springframework .core .BridgeMethodResolver ;
35
34
import org .springframework .util .Assert ;
35
+ import org .springframework .util .ConcurrentReferenceHashMap ;
36
36
import org .springframework .util .ObjectUtils ;
37
37
import org .springframework .util .ReflectionUtils ;
38
38
@@ -68,7 +68,11 @@ public abstract class AnnotationUtils {
68
68
69
69
private static final Log logger = LogFactory .getLog (AnnotationUtils .class );
70
70
71
- private static final Map <Class <?>, Boolean > annotatedInterfaceCache = new WeakHashMap <Class <?>, Boolean >();
71
+ private static final Map <AnnotationCacheKey , Annotation > findAnnotationCache =
72
+ new ConcurrentReferenceHashMap <AnnotationCacheKey , Annotation >(256 );
73
+
74
+ private static final Map <Class <?>, Boolean > annotatedInterfaceCache =
75
+ new ConcurrentReferenceHashMap <Class <?>, Boolean >(256 );
72
76
73
77
74
78
/**
@@ -222,32 +226,40 @@ public static <A extends Annotation> Set<A> getRepeatableAnnotation(AnnotatedEle
222
226
* @param annotationType the annotation type to look for
223
227
* @return the annotation found, or {@code null} if none
224
228
*/
229
+ @ SuppressWarnings ("unchecked" )
225
230
public static <A extends Annotation > A findAnnotation (Method method , Class <A > annotationType ) {
226
- A annotation = getAnnotation (method , annotationType );
227
- Class <?> clazz = method .getDeclaringClass ();
228
- if (annotation == null ) {
229
- annotation = searchOnInterfaces (method , annotationType , clazz .getInterfaces ());
230
- }
231
- while (annotation == null ) {
232
- clazz = clazz .getSuperclass ();
233
- if (clazz == null || clazz .equals (Object .class )) {
234
- break ;
235
- }
236
- try {
237
- Method equivalentMethod = clazz .getDeclaredMethod (method .getName (), method .getParameterTypes ());
238
- annotation = getAnnotation (equivalentMethod , annotationType );
231
+ AnnotationCacheKey cacheKey = new AnnotationCacheKey (method , annotationType );
232
+ A result = (A ) findAnnotationCache .get (cacheKey );
233
+ if (result == null ) {
234
+ result = getAnnotation (method , annotationType );
235
+ Class <?> clazz = method .getDeclaringClass ();
236
+ if (result == null ) {
237
+ result = searchOnInterfaces (method , annotationType , clazz .getInterfaces ());
239
238
}
240
- catch (NoSuchMethodException ex ) {
241
- // No equivalent method found
239
+ while (result == null ) {
240
+ clazz = clazz .getSuperclass ();
241
+ if (clazz == null || clazz .equals (Object .class )) {
242
+ break ;
243
+ }
244
+ try {
245
+ Method equivalentMethod = clazz .getDeclaredMethod (method .getName (), method .getParameterTypes ());
246
+ result = getAnnotation (equivalentMethod , annotationType );
247
+ }
248
+ catch (NoSuchMethodException ex ) {
249
+ // No equivalent method found
250
+ }
251
+ if (result == null ) {
252
+ result = searchOnInterfaces (method , annotationType , clazz .getInterfaces ());
253
+ }
242
254
}
243
- if (annotation = = null ) {
244
- annotation = searchOnInterfaces ( method , annotationType , clazz . getInterfaces () );
255
+ if (result ! = null ) {
256
+ findAnnotationCache . put ( cacheKey , result );
245
257
}
246
258
}
247
- return annotation ;
259
+ return result ;
248
260
}
249
261
250
- private static <A extends Annotation > A searchOnInterfaces (Method method , Class <A > annotationType , Class <?>[] ifcs ) {
262
+ private static <A extends Annotation > A searchOnInterfaces (Method method , Class <A > annotationType , Class <?>... ifcs ) {
251
263
A annotation = null ;
252
264
for (Class <?> iface : ifcs ) {
253
265
if (isInterfaceWithAnnotatedMethods (iface )) {
@@ -267,30 +279,28 @@ private static <A extends Annotation> A searchOnInterfaces(Method method, Class<
267
279
}
268
280
269
281
private static boolean isInterfaceWithAnnotatedMethods (Class <?> iface ) {
270
- synchronized (annotatedInterfaceCache ) {
271
- Boolean flag = annotatedInterfaceCache .get (iface );
272
- if (flag != null ) {
273
- return flag ;
274
- }
275
- boolean found = false ;
276
- for (Method ifcMethod : iface .getMethods ()) {
277
- try {
278
- if (ifcMethod .getAnnotations ().length > 0 ) {
279
- found = true ;
280
- break ;
281
- }
282
+ Boolean flag = annotatedInterfaceCache .get (iface );
283
+ if (flag != null ) {
284
+ return flag ;
285
+ }
286
+ boolean found = false ;
287
+ for (Method ifcMethod : iface .getMethods ()) {
288
+ try {
289
+ if (ifcMethod .getAnnotations ().length > 0 ) {
290
+ found = true ;
291
+ break ;
282
292
}
283
- catch ( Exception ex ) {
284
- // Assuming nested Class values not resolvable within annotation attributes...
285
- // We're probably hitting a non-present optional arrangement - let's back out .
286
- if ( logger . isInfoEnabled ()) {
287
- logger .info ( "Failed to introspect annotations on [" + ifcMethod + "]: " + ex );
288
- }
293
+ }
294
+ catch ( Exception ex ) {
295
+ // Assuming nested Class values not resolvable within annotation attributes.. .
296
+ // We're probably hitting a non-present optional arrangement - let's back out.
297
+ if ( logger .isInfoEnabled ()) {
298
+ logger . info ( "Failed to introspect annotations on [" + ifcMethod + "]: " + ex );
289
299
}
290
300
}
291
- annotatedInterfaceCache .put (iface , found );
292
- return found ;
293
301
}
302
+ annotatedInterfaceCache .put (iface , found );
303
+ return found ;
294
304
}
295
305
296
306
/**
@@ -315,8 +325,17 @@ private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
315
325
* @param annotationType the type of annotation to look for
316
326
* @return the annotation if found, or {@code null} if not found
317
327
*/
328
+ @ SuppressWarnings ("unchecked" )
318
329
public static <A extends Annotation > A findAnnotation (Class <?> clazz , Class <A > annotationType ) {
319
- return findAnnotation (clazz , annotationType , new HashSet <Annotation >());
330
+ AnnotationCacheKey cacheKey = new AnnotationCacheKey (clazz , annotationType );
331
+ A result = (A ) findAnnotationCache .get (cacheKey );
332
+ if (result == null ) {
333
+ result = findAnnotation (clazz , annotationType , new HashSet <Annotation >());
334
+ if (result != null ) {
335
+ findAnnotationCache .put (cacheKey , result );
336
+ }
337
+ }
338
+ return result ;
320
339
}
321
340
322
341
/**
@@ -676,6 +695,40 @@ public static Object getDefaultValue(Class<? extends Annotation> annotationType,
676
695
}
677
696
678
697
698
+ /**
699
+ * Default cache key for the TransactionAttribute cache.
700
+ */
701
+ private static class AnnotationCacheKey {
702
+
703
+ private final AnnotatedElement element ;
704
+
705
+ private final Class <? extends Annotation > annotationType ;
706
+
707
+ public AnnotationCacheKey (AnnotatedElement element , Class <? extends Annotation > annotationType ) {
708
+ this .element = element ;
709
+ this .annotationType = annotationType ;
710
+ }
711
+
712
+ @ Override
713
+ public boolean equals (Object other ) {
714
+ if (this == other ) {
715
+ return true ;
716
+ }
717
+ if (!(other instanceof AnnotationCacheKey )) {
718
+ return false ;
719
+ }
720
+ AnnotationCacheKey otherKey = (AnnotationCacheKey ) other ;
721
+ return (this .element .equals (otherKey .element ) &&
722
+ ObjectUtils .nullSafeEquals (this .annotationType , otherKey .annotationType ));
723
+ }
724
+
725
+ @ Override
726
+ public int hashCode () {
727
+ return (this .element .hashCode () * 29 + this .annotationType .hashCode ());
728
+ }
729
+ }
730
+
731
+
679
732
private static class AnnotationCollector <A extends Annotation > {
680
733
681
734
private final Class <? extends Annotation > containerAnnotationType ;
0 commit comments