Skip to content

Commit 5f7a6a0

Browse files
committed
Align validation metadata handling in PayloadMethodArgumentResolver
Reuses ValidationAnnotationUtils which is slightly optimized for the detection of Spring's Validated annotation now, also to the benefit of common web scenarios. Closes gh-21852 (cherry picked from commit c7269fe)
1 parent 4326c53 commit 5f7a6a0

File tree

3 files changed

+37
-32
lines changed

3 files changed

+37
-32
lines changed

spring-context/src/main/java/org/springframework/validation/annotation/ValidationAnnotationUtils.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,37 +26,46 @@
2626
* Mainly for internal use within the framework.
2727
*
2828
* @author Christoph Dreis
29+
* @author Juergen Hoeller
2930
* @since 5.3.7
3031
*/
3132
public abstract class ValidationAnnotationUtils {
3233

3334
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
3435

36+
3537
/**
3638
* Determine any validation hints by the given annotation.
37-
* <p>This implementation checks for {@code @javax.validation.Valid},
38-
* Spring's {@link org.springframework.validation.annotation.Validated},
39-
* and custom annotations whose name starts with "Valid".
39+
* <p>This implementation checks for Spring's
40+
* {@link org.springframework.validation.annotation.Validated},
41+
* {@code @javax.validation.Valid}, and custom annotations whose
42+
* name starts with "Valid" which may optionally declare validation
43+
* hints through the "value" attribute.
4044
* @param ann the annotation (potentially a validation annotation)
4145
* @return the validation hints to apply (possibly an empty array),
4246
* or {@code null} if this annotation does not trigger any validation
4347
*/
4448
@Nullable
4549
public static Object[] determineValidationHints(Annotation ann) {
50+
// Direct presence of @Validated ?
51+
if (ann instanceof Validated) {
52+
return ((Validated) ann).value();
53+
}
54+
// Direct presence of @Valid ?
4655
Class<? extends Annotation> annotationType = ann.annotationType();
47-
String annotationName = annotationType.getName();
48-
if ("javax.validation.Valid".equals(annotationName)) {
56+
if ("javax.validation.Valid".equals(annotationType.getName())) {
4957
return EMPTY_OBJECT_ARRAY;
5058
}
59+
// Meta presence of @Validated ?
5160
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
5261
if (validatedAnn != null) {
53-
Object hints = validatedAnn.value();
54-
return convertValidationHints(hints);
62+
return validatedAnn.value();
5563
}
64+
// Custom validation annotation ?
5665
if (annotationType.getSimpleName().startsWith("Valid")) {
57-
Object hints = AnnotationUtils.getValue(ann);
58-
return convertValidationHints(hints);
66+
return convertValidationHints(AnnotationUtils.getValue(ann));
5967
}
68+
// No validation triggered
6069
return null;
6170
}
6271

spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/reactive/PayloadMethodArgumentResolver.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@
3434
import org.springframework.core.ReactiveAdapter;
3535
import org.springframework.core.ReactiveAdapterRegistry;
3636
import org.springframework.core.ResolvableType;
37-
import org.springframework.core.annotation.AnnotationUtils;
3837
import org.springframework.core.codec.Decoder;
3938
import org.springframework.core.codec.DecodingException;
4039
import org.springframework.core.io.buffer.DataBuffer;
@@ -55,17 +54,17 @@
5554
import org.springframework.validation.BeanPropertyBindingResult;
5655
import org.springframework.validation.SmartValidator;
5756
import org.springframework.validation.Validator;
58-
import org.springframework.validation.annotation.Validated;
57+
import org.springframework.validation.annotation.ValidationAnnotationUtils;
5958

6059
/**
6160
* A resolver to extract and decode the payload of a message using a
62-
* {@link Decoder}, where the payload is expected to be a {@link Publisher} of
63-
* {@link DataBuffer DataBuffer}.
61+
* {@link Decoder}, where the payload is expected to be a {@link Publisher}
62+
* of {@link DataBuffer DataBuffer}.
6463
*
6564
* <p>Validation is applied if the method argument is annotated with
66-
* {@code @javax.validation.Valid} or
67-
* {@link org.springframework.validation.annotation.Validated}. Validation
68-
* failure results in an {@link MethodArgumentNotValidException}.
65+
* {@link org.springframework.validation.annotation.Validated} or
66+
* {@code @javax.validation.Valid}. Validation failure results in an
67+
* {@link MethodArgumentNotValidException}.
6968
*
7069
* <p>This resolver should be ordered last if {@link #useDefaultResolution} is
7170
* set to {@code true} since in that case it supports all types and does not
@@ -287,10 +286,8 @@ private Consumer<Object> getValidator(Message<?> message, MethodParameter parame
287286
return null;
288287
}
289288
for (Annotation ann : parameter.getParameterAnnotations()) {
290-
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
291-
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
292-
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
293-
Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
289+
Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
290+
if (validationHints != null) {
294291
String name = Conventions.getVariableNameForParameter(parameter);
295292
return target -> {
296293
BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(target, name);

spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadMethodArgumentResolver.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.lang.annotation.Annotation;
2020

2121
import org.springframework.core.MethodParameter;
22-
import org.springframework.core.annotation.AnnotationUtils;
2322
import org.springframework.lang.Nullable;
2423
import org.springframework.messaging.Message;
2524
import org.springframework.messaging.converter.MessageConversionException;
@@ -36,12 +35,16 @@
3635
import org.springframework.validation.ObjectError;
3736
import org.springframework.validation.SmartValidator;
3837
import org.springframework.validation.Validator;
39-
import org.springframework.validation.annotation.Validated;
38+
import org.springframework.validation.annotation.ValidationAnnotationUtils;
4039

4140
/**
4241
* A resolver to extract and convert the payload of a message using a
43-
* {@link MessageConverter}. It also validates the payload using a
44-
* {@link Validator} if the argument is annotated with a Validation annotation.
42+
* {@link MessageConverter}.
43+
*
44+
* <p>Validation is applied if the method argument is annotated with
45+
* {@link org.springframework.validation.annotation.Validated} or
46+
* {@code @javax.validation.Valid}. Validation failure results in an
47+
* {@link MethodArgumentNotValidException}.
4548
*
4649
* <p>This {@link HandlerMethodArgumentResolver} should be ordered last as it
4750
* supports all types and does not require the {@link Payload} annotation.
@@ -190,8 +193,6 @@ protected Class<?> resolveTargetClass(MethodParameter parameter, Message<?> mess
190193

191194
/**
192195
* Validate the payload if applicable.
193-
* <p>The default implementation checks for {@code @javax.validation.Valid},
194-
* Spring's {@link Validated}, and custom annotations whose name starts with "Valid".
195196
* @param message the currently processed message
196197
* @param parameter the method parameter
197198
* @param target the target payload object
@@ -202,10 +203,8 @@ protected void validate(Message<?> message, MethodParameter parameter, Object ta
202203
return;
203204
}
204205
for (Annotation ann : parameter.getParameterAnnotations()) {
205-
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
206-
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
207-
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
208-
Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
206+
Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
207+
if (validationHints != null) {
209208
BeanPropertyBindingResult bindingResult =
210209
new BeanPropertyBindingResult(target, getParameterName(parameter));
211210
if (!ObjectUtils.isEmpty(validationHints) && this.validator instanceof SmartValidator) {

0 commit comments

Comments
 (0)