@@ -63,31 +63,45 @@ private ValidationHelper(Validator validator) {
6363 @ Nullable
6464 public Consumer <Object []> getValidationHelperFor (HandlerMethod handlerMethod ) {
6565
66- boolean required = false ;
67- Class <?>[] groups = null ;
66+ boolean requiresMethodValidation = false ;
67+ Class <?>[] methodValidationGroups = null ;
6868
6969 Validated validatedAnnotation = findAnnotation (handlerMethod , Validated .class );
7070 if (validatedAnnotation != null ) {
71- required = true ;
72- groups = validatedAnnotation .value ();
71+ requiresMethodValidation = true ;
72+ methodValidationGroups = validatedAnnotation .value ();
7373 }
7474 else if (findAnnotation (handlerMethod , Valid .class ) != null ) {
75- required = true ;
75+ requiresMethodValidation = true ;
7676 }
7777
78- for (MethodParameter parameter : handlerMethod .getMethodParameters ()) {
79- if (required ) {
80- break ;
81- }
78+ Consumer <Object []> parameterValidator = null ;
79+ MethodParameter [] parameters = handlerMethod .getMethodParameters ();
80+
81+ for (int i = 0 ; i < parameters .length ; i ++) {
82+ MethodParameter parameter = parameters [i ];
8283 for (Annotation annot : parameter .getParameterAnnotations ()) {
8384 MergedAnnotations merged = MergedAnnotations .from (annot );
84- if (merged .isPresent (Valid .class ) || merged .isPresent (Constraint .class ) || merged .isPresent (Validated .class )) {
85- required = true ;
85+ if (merged .isPresent (Valid .class ) || merged .isPresent (Constraint .class )) {
86+ requiresMethodValidation = true ;
87+ }
88+ else if (annot .annotationType ().equals (Validated .class )) {
89+ Class <?>[] groups = ((Validated ) annot ).value ();
90+ parameterValidator = (parameterValidator != null ?
91+ parameterValidator .andThen (new MethodParameterValidator (i , groups )) :
92+ new MethodParameterValidator (i , groups ));
8693 }
8794 }
8895 }
8996
90- return (required ? new HandlerMethodValidator (handlerMethod , groups ) : null );
97+ Consumer <Object []> result = (requiresMethodValidation ?
98+ new HandlerMethodValidator (handlerMethod , methodValidationGroups ) : null );
99+
100+ if (parameterValidator != null ) {
101+ return (result != null ? result .andThen (parameterValidator ) : parameterValidator );
102+ }
103+
104+ return result ;
91105 }
92106
93107 @ Nullable
@@ -131,10 +145,9 @@ private class HandlerMethodValidator implements Consumer<Object[]> {
131145
132146 private final HandlerMethod handlerMethod ;
133147
134- @ Nullable
135148 private final Class <?>[] validationGroups ;
136149
137- private HandlerMethodValidator (HandlerMethod handlerMethod , @ Nullable Class <?>[] validationGroups ) {
150+ HandlerMethodValidator (HandlerMethod handlerMethod , @ Nullable Class <?>[] validationGroups ) {
138151 Assert .notNull (handlerMethod , "HandlerMethod is required" );
139152 this .handlerMethod = handlerMethod ;
140153 this .validationGroups = (validationGroups != null ? validationGroups : new Class <?>[] {});
@@ -143,12 +156,41 @@ private HandlerMethodValidator(HandlerMethod handlerMethod, @Nullable Class<?>[]
143156 @ Override
144157 public void accept (Object [] arguments ) {
145158
146- Set <ConstraintViolation <Object >> result =
159+ Set <ConstraintViolation <Object >> violations =
147160 ValidationHelper .this .validator .forExecutables ().validateParameters (
148161 this .handlerMethod .getBean (), this .handlerMethod .getMethod (), arguments , this .validationGroups );
149162
150- if (!result .isEmpty ()) {
151- throw new ConstraintViolationException (result );
163+ if (!violations .isEmpty ()) {
164+ throw new ConstraintViolationException (violations );
165+ }
166+ }
167+ }
168+
169+
170+ /**
171+ * Callback to apply validation to a {@link MethodParameter}, typically
172+ * because it's annotated with Spring's {@code @Validated} rather than with
173+ * {@code @Valid}.
174+ */
175+ private class MethodParameterValidator implements Consumer <Object []> {
176+
177+ private final int index ;
178+
179+ private final Class <?>[] validationGroups ;
180+
181+ MethodParameterValidator (int index , @ Nullable Class <?>[] validationGroups ) {
182+ this .index = index ;
183+ this .validationGroups = (validationGroups != null ? validationGroups : new Class <?>[] {});
184+ }
185+
186+ @ Override
187+ public void accept (Object [] arguments ) {
188+
189+ Set <ConstraintViolation <Object >> violations =
190+ ValidationHelper .this .validator .validate (arguments [this .index ], this .validationGroups );
191+
192+ if (!violations .isEmpty ()) {
193+ throw new ConstraintViolationException (violations );
152194 }
153195 }
154196 }
0 commit comments