|
20 | 20 | import java.lang.reflect.AnnotatedElement;
|
21 | 21 | import java.lang.reflect.Executable;
|
22 | 22 | import java.lang.reflect.Method;
|
| 23 | +import java.lang.reflect.Modifier; |
23 | 24 | import java.lang.reflect.Parameter;
|
24 | 25 | import java.util.ArrayList;
|
| 26 | +import java.util.Arrays; |
25 | 27 | import java.util.Collections;
|
26 | 28 | import java.util.HashSet;
|
27 | 29 | import java.util.List;
|
|
30 | 32 | import java.util.concurrent.ConcurrentHashMap;
|
31 | 33 |
|
32 | 34 | import org.springframework.core.MethodClassKey;
|
| 35 | +import org.springframework.core.ResolvableType; |
33 | 36 | import org.springframework.core.annotation.AnnotationConfigurationException;
|
34 | 37 | import org.springframework.core.annotation.MergedAnnotation;
|
35 | 38 | import org.springframework.core.annotation.MergedAnnotations;
|
@@ -221,18 +224,15 @@ private List<MergedAnnotation<A>> findClosestMethodAnnotations(Method method, Cl
|
221 | 224 | return Collections.emptyList();
|
222 | 225 | }
|
223 | 226 | classesToSkip.add(targetClass);
|
224 |
| - try { |
225 |
| - Method methodToUse = targetClass.getDeclaredMethod(method.getName(), method.getParameterTypes()); |
| 227 | + Method methodToUse = findMethod(method, targetClass); |
| 228 | + if (methodToUse != null) { |
226 | 229 | List<MergedAnnotation<A>> annotations = findDirectAnnotations(methodToUse);
|
227 | 230 | if (!annotations.isEmpty()) {
|
228 | 231 | return annotations;
|
229 | 232 | }
|
230 | 233 | }
|
231 |
| - catch (NoSuchMethodException ex) { |
232 |
| - // move on |
233 |
| - } |
234 |
| - List<MergedAnnotation<A>> annotations = new ArrayList<>(); |
235 |
| - annotations.addAll(findClosestMethodAnnotations(method, targetClass.getSuperclass(), classesToSkip)); |
| 234 | + List<MergedAnnotation<A>> annotations = new ArrayList<>( |
| 235 | + findClosestMethodAnnotations(method, targetClass.getSuperclass(), classesToSkip)); |
236 | 236 | for (Class<?> inter : targetClass.getInterfaces()) {
|
237 | 237 | annotations.addAll(findClosestMethodAnnotations(method, inter, classesToSkip));
|
238 | 238 | }
|
@@ -264,4 +264,52 @@ private List<MergedAnnotation<A>> findDirectAnnotations(AnnotatedElement element
|
264 | 264 | .toList();
|
265 | 265 | }
|
266 | 266 |
|
| 267 | + private static Method findMethod(Method method, Class<?> targetClass) { |
| 268 | + for (Method candidate : targetClass.getDeclaredMethods()) { |
| 269 | + if (candidate == method) { |
| 270 | + return candidate; |
| 271 | + } |
| 272 | + if (isOverride(method, candidate)) { |
| 273 | + return candidate; |
| 274 | + } |
| 275 | + } |
| 276 | + return null; |
| 277 | + } |
| 278 | + |
| 279 | + private static boolean isOverride(Method rootMethod, Method candidateMethod) { |
| 280 | + return (!Modifier.isPrivate(candidateMethod.getModifiers()) |
| 281 | + && candidateMethod.getName().equals(rootMethod.getName()) |
| 282 | + && hasSameParameterTypes(rootMethod, candidateMethod)); |
| 283 | + } |
| 284 | + |
| 285 | + private static boolean hasSameParameterTypes(Method rootMethod, Method candidateMethod) { |
| 286 | + if (candidateMethod.getParameterCount() != rootMethod.getParameterCount()) { |
| 287 | + return false; |
| 288 | + } |
| 289 | + Class<?>[] rootParameterTypes = rootMethod.getParameterTypes(); |
| 290 | + Class<?>[] candidateParameterTypes = candidateMethod.getParameterTypes(); |
| 291 | + if (Arrays.equals(candidateParameterTypes, rootParameterTypes)) { |
| 292 | + return true; |
| 293 | + } |
| 294 | + return hasSameGenericTypeParameters(rootMethod, candidateMethod, rootParameterTypes); |
| 295 | + } |
| 296 | + |
| 297 | + private static boolean hasSameGenericTypeParameters(Method rootMethod, Method candidateMethod, |
| 298 | + Class<?>[] rootParameterTypes) { |
| 299 | + |
| 300 | + Class<?> sourceDeclaringClass = rootMethod.getDeclaringClass(); |
| 301 | + Class<?> candidateDeclaringClass = candidateMethod.getDeclaringClass(); |
| 302 | + if (!candidateDeclaringClass.isAssignableFrom(sourceDeclaringClass)) { |
| 303 | + return false; |
| 304 | + } |
| 305 | + for (int i = 0; i < rootParameterTypes.length; i++) { |
| 306 | + Class<?> resolvedParameterType = ResolvableType.forMethodParameter(candidateMethod, i, sourceDeclaringClass) |
| 307 | + .resolve(); |
| 308 | + if (rootParameterTypes[i] != resolvedParameterType) { |
| 309 | + return false; |
| 310 | + } |
| 311 | + } |
| 312 | + return true; |
| 313 | + } |
| 314 | + |
267 | 315 | }
|
0 commit comments