diff --git a/org.springframework.core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/org.springframework.core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index 754ed3f57f9..860c6423329 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/org.springframework.core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -21,6 +21,7 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.WeakHashMap; import org.springframework.core.BridgeMethodResolver; import org.springframework.util.Assert; @@ -50,6 +51,8 @@ public abstract class AnnotationUtils { /** The attribute name for annotations with a single element */ static final String VALUE = "value"; + private static final Map annotatedInterfaceCache = new WeakHashMap(); + /** * Get all {@link Annotation Annotations} from the supplied {@link Method}. @@ -120,26 +123,45 @@ public abstract class AnnotationUtils { private static A searchOnInterfaces(Method method, Class annotationType, Class[] ifcs) { A annotation = null; for (Class iface : ifcs) { - Method equivalentMethod; - try { - equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes()); - annotation = getAnnotation(equivalentMethod, annotationType); + if (isInterfaceWithAnnotatedMethods(iface)) { + try { + Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes()); + annotation = getAnnotation(equivalentMethod, annotationType); + } + catch (NoSuchMethodException ex) { + // Skip this interface - it doesn't have the method... + } + if (annotation != null) { + break; + } } - catch (NoSuchMethodException e) { - // skip this interface - it doesn't have the method + } + return annotation; + } + + private static boolean isInterfaceWithAnnotatedMethods(Class iface) { + synchronized (annotatedInterfaceCache) { + Boolean flag = annotatedInterfaceCache.get(iface); + if (flag != null) { + return flag; } - if (annotation != null) { - break; + boolean found = false; + for (Method ifcMethod : iface.getMethods()) { + if (ifcMethod.getAnnotations().length > 0) { + found = true; + break; + } } + annotatedInterfaceCache.put(iface, found); + return found; } - return annotation; } /** * Find a single {@link Annotation} of annotationType from the supplied {@link Class}, - * traversing its interfaces and super classes if no annotation can be found on the given class itself. + * traversing its interfaces and superclasses if no annotation can be found on the given class itself. *

This method explicitly handles class-level annotations which are not declared as - * {@link Inherited inherited} as well as annotations on interfaces. + * {@link java.lang.annotation.Inherited inherited} as well as annotations on interfaces. *

The algorithm operates as follows: Searches for an annotation on the given class and returns * it if found. Else searches all interfaces that the given class declares, returning the annotation * from the first matching candidate, if any. Else proceeds with introspection of the superclass @@ -171,7 +193,7 @@ public abstract class AnnotationUtils { } } Class superClass = clazz.getSuperclass(); - if (superClass == null || superClass.equals(Object.class)) { + if (superClass == null || superClass == Object.class) { return null; } return findAnnotation(superClass, annotationType);