|
21 | 21 | import java.util.Arrays;
|
22 | 22 | import java.util.HashMap;
|
23 | 23 | import java.util.Map;
|
| 24 | +import java.util.WeakHashMap; |
24 | 25 |
|
25 | 26 | import org.springframework.core.BridgeMethodResolver;
|
26 | 27 | import org.springframework.util.Assert;
|
@@ -50,6 +51,8 @@ public abstract class AnnotationUtils {
|
50 | 51 | /** The attribute name for annotations with a single element */
|
51 | 52 | static final String VALUE = "value";
|
52 | 53 |
|
| 54 | + private static final Map<Class, Boolean> annotatedInterfaceCache = new WeakHashMap<Class, Boolean>(); |
| 55 | + |
53 | 56 |
|
54 | 57 | /**
|
55 | 58 | * Get all {@link Annotation Annotations} from the supplied {@link Method}.
|
@@ -120,26 +123,45 @@ public static <A extends Annotation> A findAnnotation(Method method, Class<A> an
|
120 | 123 | private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class[] ifcs) {
|
121 | 124 | A annotation = null;
|
122 | 125 | for (Class<?> iface : ifcs) {
|
123 |
| - Method equivalentMethod; |
124 |
| - try { |
125 |
| - equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes()); |
126 |
| - annotation = getAnnotation(equivalentMethod, annotationType); |
| 126 | + if (isInterfaceWithAnnotatedMethods(iface)) { |
| 127 | + try { |
| 128 | + Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes()); |
| 129 | + annotation = getAnnotation(equivalentMethod, annotationType); |
| 130 | + } |
| 131 | + catch (NoSuchMethodException ex) { |
| 132 | + // Skip this interface - it doesn't have the method... |
| 133 | + } |
| 134 | + if (annotation != null) { |
| 135 | + break; |
| 136 | + } |
127 | 137 | }
|
128 |
| - catch (NoSuchMethodException e) { |
129 |
| - // skip this interface - it doesn't have the method |
| 138 | + } |
| 139 | + return annotation; |
| 140 | + } |
| 141 | + |
| 142 | + private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) { |
| 143 | + synchronized (annotatedInterfaceCache) { |
| 144 | + Boolean flag = annotatedInterfaceCache.get(iface); |
| 145 | + if (flag != null) { |
| 146 | + return flag; |
130 | 147 | }
|
131 |
| - if (annotation != null) { |
132 |
| - break; |
| 148 | + boolean found = false; |
| 149 | + for (Method ifcMethod : iface.getMethods()) { |
| 150 | + if (ifcMethod.getAnnotations().length > 0) { |
| 151 | + found = true; |
| 152 | + break; |
| 153 | + } |
133 | 154 | }
|
| 155 | + annotatedInterfaceCache.put(iface, found); |
| 156 | + return found; |
134 | 157 | }
|
135 |
| - return annotation; |
136 | 158 | }
|
137 | 159 |
|
138 | 160 | /**
|
139 | 161 | * Find a single {@link Annotation} of <code>annotationType</code> from the supplied {@link Class},
|
140 |
| - * traversing its interfaces and super classes if no annotation can be found on the given class itself. |
| 162 | + * traversing its interfaces and superclasses if no annotation can be found on the given class itself. |
141 | 163 | * <p>This method explicitly handles class-level annotations which are not declared as
|
142 |
| - * {@link Inherited inherited} <i>as well as annotations on interfaces</i>. |
| 164 | + * {@link java.lang.annotation.Inherited inherited} <i>as well as annotations on interfaces</i>. |
143 | 165 | * <p>The algorithm operates as follows: Searches for an annotation on the given class and returns
|
144 | 166 | * it if found. Else searches all interfaces that the given class declares, returning the annotation
|
145 | 167 | * from the first matching candidate, if any. Else proceeds with introspection of the superclass
|
@@ -171,7 +193,7 @@ public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> a
|
171 | 193 | }
|
172 | 194 | }
|
173 | 195 | Class<?> superClass = clazz.getSuperclass();
|
174 |
| - if (superClass == null || superClass.equals(Object.class)) { |
| 196 | + if (superClass == null || superClass == Object.class) { |
175 | 197 | return null;
|
176 | 198 | }
|
177 | 199 | return findAnnotation(superClass, annotationType);
|
|
0 commit comments