|
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