From 8fb119df1ecc97d4391276b02189fc32c3e7bf46 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 11 Feb 2026 09:00:52 +0000 Subject: [PATCH] Determine validation groups in HandlerMethod Closes gh-36274 --- .../web/method/HandlerMethod.java | 26 +++++++++++++++++++ .../support/InvocableHandlerMethod.java | 9 ++----- 2 files changed, 28 insertions(+), 7 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 04aef80e148..ba369b21d6b 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 @@ -48,6 +48,7 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; +import org.springframework.validation.annotation.ValidationAnnotationUtils; import org.springframework.web.bind.annotation.ResponseStatus; /** @@ -72,6 +73,8 @@ public class HandlerMethod extends AnnotatedMethod { /** Logger that is available to subclasses. */ protected static final Log logger = LogFactory.getLog(HandlerMethod.class); + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + private final Object bean; @@ -85,6 +88,8 @@ public class HandlerMethod extends AnnotatedMethod { private final boolean validateReturnValue; + private Class @Nullable [] validationGroups; + private @Nullable HttpStatusCode responseStatus; private @Nullable String responseStatusReason; @@ -191,16 +196,25 @@ public class HandlerMethod extends AnnotatedMethod { this.beanFactory = handlerMethod.beanFactory; this.messageSource = handlerMethod.messageSource; this.beanType = handlerMethod.beanType; + this.validateArguments = (initValidateFlags ? MethodValidationInitializer.checkArguments(this.beanType, getMethodParameters()) : handlerMethod.validateArguments); + this.validateReturnValue = (initValidateFlags ? MethodValidationInitializer.checkReturnValue(this.beanType, getBridgedMethod()) : handlerMethod.validateReturnValue); + + this.validationGroups = (handler != null && (shouldValidateArguments() || shouldValidateReturnValue()) ? + ValidationAnnotationUtils.determineValidationGroups(handler, getBridgedMethod()) : + handlerMethod.validationGroups); + this.responseStatus = handlerMethod.responseStatus; this.responseStatusReason = handlerMethod.responseStatusReason; + this.resolvedFromHandlerMethod = (handlerMethod.resolvedFromHandlerMethod != null ? handlerMethod.resolvedFromHandlerMethod : handlerMethod); + this.description = handlerMethod.toString(); } @@ -281,6 +295,18 @@ public class HandlerMethod extends AnnotatedMethod { return this.validateReturnValue; } + /** + * Return validation groups declared in + * {@link org.springframework.validation.annotation.Validated @Validated} + * either on the method, or on the containing target class of the method, or + * for an AOP proxy without a target (with all behavior in advisors), also + * check on proxied interfaces. + * @since 7.0.4 + */ + public Class[] getValidationGroups() { + return (this.validationGroups != null ? this.validationGroups : EMPTY_CLASS_ARRAY); + } + /** * Return the specified response status, if any. * @since 4.3.8 diff --git a/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java b/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java index 65bc8821288..be6f82ecdf5 100644 --- a/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java +++ b/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java @@ -43,7 +43,6 @@ import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; -import org.springframework.validation.annotation.ValidationAnnotationUtils; import org.springframework.validation.method.MethodValidator; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.SessionStatus; @@ -78,8 +77,6 @@ public class InvocableHandlerMethod extends HandlerMethod { private @Nullable MethodValidator methodValidator; - private Class[] validationGroups = EMPTY_GROUPS; - /** * Create an instance from a {@code HandlerMethod}. @@ -151,8 +148,6 @@ public class InvocableHandlerMethod extends HandlerMethod { */ public void setMethodValidator(@Nullable MethodValidator methodValidator) { this.methodValidator = methodValidator; - this.validationGroups = (methodValidator != null && (shouldValidateArguments() || shouldValidateReturnValue()) ? - ValidationAnnotationUtils.determineValidationGroups(getBean(), getBridgedMethod()) : EMPTY_GROUPS); } @@ -185,14 +180,14 @@ public class InvocableHandlerMethod extends HandlerMethod { if (shouldValidateArguments() && this.methodValidator != null) { this.methodValidator.applyArgumentValidation( - getBean(), getBridgedMethod(), getMethodParameters(), args, this.validationGroups); + getBean(), getBridgedMethod(), getMethodParameters(), args, getValidationGroups()); } Object returnValue = doInvoke(args); if (shouldValidateReturnValue() && this.methodValidator != null) { this.methodValidator.applyReturnValueValidation( - getBean(), getBridgedMethod(), getReturnType(), returnValue, this.validationGroups); + getBean(), getBridgedMethod(), getReturnType(), returnValue, getValidationGroups()); } return returnValue;