From 1f5d0faf1f3a1ee1b8e26b76cd72a5fab3c2839b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 19 Jul 2018 11:38:10 +0200 Subject: [PATCH] HandlerMethod caches interface parameter annotations Issue: SPR-11055 --- .../web/method/HandlerMethod.java | 79 +++++++++++++------ 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java b/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java index f4e911739c..0ae0c1f5ee 100644 --- a/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java +++ b/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java @@ -29,6 +29,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.core.BridgeMethodResolver; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.http.HttpStatus; @@ -81,6 +82,9 @@ public class HandlerMethod { @Nullable private HandlerMethod resolvedFromHandlerMethod; + @Nullable + private volatile List interfaceParameterAnnotations; + /** * Create an instance from a bean instance and a method. @@ -323,8 +327,43 @@ public class HandlerMethod { * @since 4.3 */ public String getShortLogMessage() { - int args = this.method.getParameterCount(); - return getBeanType().getName() + "#" + this.method.getName() + "[" + args + " args]"; + return getBeanType().getName() + "#" + this.method.getName() + + "[" + this.method.getParameterCount() + " args]"; + } + + + private List getInterfaceParameterAnnotations() { + List parameterAnnotations = this.interfaceParameterAnnotations; + if (parameterAnnotations == null) { + parameterAnnotations = new ArrayList<>(); + for (Class ifc : this.method.getDeclaringClass().getInterfaces()) { + for (Method candidate : ifc.getMethods()) { + if (isOverrideFor(candidate)) { + parameterAnnotations.add(candidate.getParameterAnnotations()); + } + } + } + this.interfaceParameterAnnotations = parameterAnnotations; + } + return parameterAnnotations; + } + + private boolean isOverrideFor(Method candidate) { + if (!candidate.getName().equals(this.method.getName()) || + candidate.getParameterCount() != this.method.getParameterCount()) { + return false; + } + Class[] paramTypes = this.method.getParameterTypes(); + if (Arrays.equals(candidate.getParameterTypes(), paramTypes)) { + return true; + } + for (int i = 0; i < paramTypes.length; i++) { + if (paramTypes[i] != + ResolvableType.forMethodParameter(candidate, i, this.method.getDeclaringClass()).resolve()) { + return false; + } + } + return true; } @@ -387,30 +426,24 @@ public class HandlerMethod { Annotation[] anns = this.combinedAnnotations; if (anns == null) { anns = super.getParameterAnnotations(); - Class[] ifcs = getDeclaringClass().getInterfaces(); - for (Class ifc : ifcs) { - try { - Method method = ifc.getMethod(getExecutable().getName(), getExecutable().getParameterTypes()); - Annotation[] paramAnns = method.getParameterAnnotations()[getParameterIndex()]; - if (paramAnns.length > 0) { - List merged = new ArrayList<>(anns.length + paramAnns.length); - merged.addAll(Arrays.asList(anns)); - for (Annotation fieldAnn : paramAnns) { - boolean existingType = false; - for (Annotation ann : anns) { - if (ann.annotationType() == fieldAnn.annotationType()) { - existingType = true; - break; - } - } - if (!existingType) { - merged.add(fieldAnn); + for (Annotation[][] ifcAnns : getInterfaceParameterAnnotations()) { + Annotation[] paramAnns = ifcAnns[getParameterIndex()]; + if (paramAnns.length > 0) { + List merged = new ArrayList<>(anns.length + paramAnns.length); + merged.addAll(Arrays.asList(anns)); + for (Annotation paramAnn : paramAnns) { + boolean existingType = false; + for (Annotation ann : anns) { + if (ann.annotationType() == paramAnn.annotationType()) { + existingType = true; + break; } } - anns = merged.toArray(new Annotation[0]); + if (!existingType) { + merged.add(paramAnn); + } } - } - catch (NoSuchMethodException ex) { + anns = merged.toArray(new Annotation[0]); } } this.combinedAnnotations = anns;