Move validation group determination to ValidationAnnotationUtils

See gh-36274
This commit is contained in:
rstoyanchev
2026-02-10 16:56:33 +00:00
parent 6507367d10
commit 1bb0fdda6b
7 changed files with 54 additions and 24 deletions
@@ -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);
}
}
@@ -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
@@ -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());
}
@@ -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(