diff --git a/spring-context/src/main/java/org/springframework/validation/annotation/ValidationAnnotationUtils.java b/spring-context/src/main/java/org/springframework/validation/annotation/ValidationAnnotationUtils.java index 66e5d18f10e..759df1ddd3c 100644 --- a/spring-context/src/main/java/org/springframework/validation/annotation/ValidationAnnotationUtils.java +++ b/spring-context/src/main/java/org/springframework/validation/annotation/ValidationAnnotationUtils.java @@ -17,9 +17,12 @@ package org.springframework.validation.annotation; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import org.jspecify.annotations.Nullable; +import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.aop.support.AopUtils; import org.springframework.core.annotation.AnnotationUtils; /** @@ -34,6 +37,8 @@ public abstract class ValidationAnnotationUtils { private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + /** * Determine any validation hints by the given annotation. @@ -76,4 +81,30 @@ public abstract class ValidationAnnotationUtils { return (hints instanceof Object[] objectHints ? objectHints : new Object[] {hints}); } + /** + * Determine the applicable validation groups from an + * {@link org.springframework.validation.annotation.Validated @Validated} + * annotation 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 static Class[] determineValidationGroups(Object target, Method method) { + Validated validatedAnn = AnnotationUtils.findAnnotation(method, Validated.class); + if (validatedAnn == null) { + if (AopUtils.isAopProxy(target)) { + for (Class type : AopProxyUtils.proxiedUserInterfaces(target)) { + validatedAnn = AnnotationUtils.findAnnotation(type, Validated.class); + if (validatedAnn != null) { + break; + } + } + } + else { + validatedAnn = AnnotationUtils.findAnnotation(target.getClass(), Validated.class); + } + } + return (validatedAnn != null ? validatedAnn.value() : EMPTY_CLASS_ARRAY); + } + } diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationAdapter.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationAdapter.java index 28ea7f3c21a..63e57687bc9 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationAdapter.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationAdapter.java @@ -40,8 +40,6 @@ import jakarta.validation.executable.ExecutableValidator; import jakarta.validation.metadata.ConstraintDescriptor; import org.jspecify.annotations.Nullable; -import org.springframework.aop.framework.AopProxyUtils; -import org.springframework.aop.support.AopUtils; import org.springframework.context.MessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.core.BridgeMethodResolver; @@ -50,7 +48,6 @@ import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; import org.springframework.util.function.SingletonSupplier; import org.springframework.validation.BeanPropertyBindingResult; @@ -59,6 +56,7 @@ import org.springframework.validation.DefaultMessageCodesResolver; import org.springframework.validation.Errors; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.annotation.Validated; +import org.springframework.validation.annotation.ValidationAnnotationUtils; import org.springframework.validation.method.MethodValidationResult; import org.springframework.validation.method.MethodValidator; import org.springframework.validation.method.ParameterErrors; @@ -213,24 +211,14 @@ public class MethodValidationAdapter implements MethodValidator { * annotation 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. + * @deprecated in favor of + * {@link org.springframework.validation.annotation.ValidationAnnotationUtils#determineValidationGroups(Object, Method)} */ + @SuppressWarnings("removal") + @Deprecated(since = "7.0.4", forRemoval = true) @Override public Class[] determineValidationGroups(Object target, Method method) { - Validated validatedAnn = AnnotationUtils.findAnnotation(method, Validated.class); - if (validatedAnn == null) { - if (AopUtils.isAopProxy(target)) { - for (Class type : AopProxyUtils.proxiedUserInterfaces(target)) { - validatedAnn = AnnotationUtils.findAnnotation(type, Validated.class); - if (validatedAnn != null) { - break; - } - } - } - else { - validatedAnn = AnnotationUtils.findAnnotation(target.getClass(), Validated.class); - } - } - return (validatedAnn != null ? validatedAnn.value() : new Class[0]); + return ValidationAnnotationUtils.determineValidationGroups(target, method); } @Override diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java index 606feb56266..a0942390597 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java @@ -46,6 +46,7 @@ import org.springframework.util.ClassUtils; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.Errors; import org.springframework.validation.annotation.Validated; +import org.springframework.validation.annotation.ValidationAnnotationUtils; import org.springframework.validation.method.MethodValidationException; import org.springframework.validation.method.MethodValidationResult; import org.springframework.validation.method.ParameterErrors; @@ -224,7 +225,7 @@ public class MethodValidationInterceptor implements MethodInterceptor { */ protected Class[] determineValidationGroups(MethodInvocation invocation) { Object target = getTarget(invocation); - return this.validationAdapter.determineValidationGroups(target, invocation.getMethod()); + return ValidationAnnotationUtils.determineValidationGroups(target, invocation.getMethod()); } diff --git a/spring-context/src/main/java/org/springframework/validation/method/MethodValidator.java b/spring-context/src/main/java/org/springframework/validation/method/MethodValidator.java index 45fce4d7984..64d4512bfbe 100644 --- a/spring-context/src/main/java/org/springframework/validation/method/MethodValidator.java +++ b/spring-context/src/main/java/org/springframework/validation/method/MethodValidator.java @@ -39,7 +39,10 @@ public interface MethodValidator { * @param target the target Object * @param method the target method * @return the applicable validation groups as a {@code Class} array + * @deprecated in favor of + * {@link org.springframework.validation.annotation.ValidationAnnotationUtils#determineValidationGroups(Object, Method)} */ + @Deprecated(since = "7.0.4", forRemoval = true) Class[] determineValidationGroups(Object target, Method method); /** @@ -48,7 +51,8 @@ public interface MethodValidator { * @param method the target method * @param parameters the parameters, if already created and available * @param arguments the candidate argument values to validate - * @param groups validation groups from {@link #determineValidationGroups} + * @param groups validation groups from + * {@link org.springframework.validation.annotation.ValidationAnnotationUtils#determineValidationGroups(Object, Method)} * @return the result of validation */ MethodValidationResult validateArguments( @@ -78,7 +82,8 @@ public interface MethodValidator { * @param method the target method * @param returnType the return parameter, if already created and available * @param returnValue the return value to validate - * @param groups validation groups from {@link #determineValidationGroups} + * @param groups validation groups from + * {@link org.springframework.validation.annotation.ValidationAnnotationUtils#determineValidationGroups(Object, Method)} * @return the result of validation */ MethodValidationResult validateReturnValue( diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/HandlerMethodValidator.java b/spring-web/src/main/java/org/springframework/web/method/annotation/HandlerMethodValidator.java index 36fc1371a23..78b889586fd 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/HandlerMethodValidator.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/HandlerMethodValidator.java @@ -28,6 +28,7 @@ import org.springframework.core.ParameterNameDiscoverer; import org.springframework.validation.BindingResult; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.SmartValidator; +import org.springframework.validation.annotation.ValidationAnnotationUtils; import org.springframework.validation.beanvalidation.MethodValidationAdapter; import org.springframework.validation.method.MethodValidationResult; import org.springframework.validation.method.MethodValidator; @@ -70,9 +71,11 @@ public final class HandlerMethodValidator implements MethodValidator { } + @SuppressWarnings("removal") + @Deprecated(since = "7.0.4", forRemoval = true) @Override public Class[] determineValidationGroups(Object target, Method method) { - return this.validationAdapter.determineValidationGroups(target, method); + return ValidationAnnotationUtils.determineValidationGroups(target, method); } @Override 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 31c46a86c63..65bc8821288 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,6 +43,7 @@ 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; @@ -151,7 +152,7 @@ public class InvocableHandlerMethod extends HandlerMethod { public void setMethodValidator(@Nullable MethodValidator methodValidator) { this.methodValidator = methodValidator; this.validationGroups = (methodValidator != null && (shouldValidateArguments() || shouldValidateReturnValue()) ? - methodValidator.determineValidationGroups(getBean(), getBridgedMethod()) : EMPTY_GROUPS); + ValidationAnnotationUtils.determineValidationGroups(getBean(), getBridgedMethod()) : EMPTY_GROUPS); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java index 5a86cf5895a..9ed371ad0b4 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java @@ -55,6 +55,7 @@ import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.lang.Contract; 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.method.HandlerMethod; import org.springframework.web.reactive.BindingContext; @@ -165,7 +166,7 @@ public class InvocableHandlerMethod extends HandlerMethod { public void setMethodValidator(@Nullable MethodValidator methodValidator) { this.methodValidator = methodValidator; this.validationGroups = (methodValidator != null ? - methodValidator.determineValidationGroups(getBean(), getBridgedMethod()) : EMPTY_GROUPS); + ValidationAnnotationUtils.determineValidationGroups(getBean(), getBridgedMethod()) : EMPTY_GROUPS); } /**