Skip to content

Commit 5e3edc6

Browse files
committed
Support @validated at method level for overriding validation groups
Issue: SPR-9174
1 parent 929cda6 commit 5e3edc6

File tree

3 files changed

+24
-6
lines changed

3 files changed

+24
-6
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2011 the original author or authors.
2+
* Copyright 2002-2014 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.
@@ -35,7 +35,11 @@
3535
* class is supposed to be validated at the method level (acting as a pointcut
3636
* for the corresponding validation interceptor), but also optionally specifying
3737
* the validation groups for method-level validation in the annotated class.
38-
* Can also be used as a meta-annotation on a custom stereotype annotation.
38+
* Applying this annotation at the method level allows for overriding the
39+
* validation groups for a specific method but does not serve as a pointcut;
40+
* a class-level annotation is nevertheless necessary to trigger method validation
41+
* for a specific bean to begin with. Can also be used as a meta-annotation on a
42+
* custom stereotype annotation or a custom group-specific validated annotation.
3943
*
4044
* @author Juergen Hoeller
4145
* @since 3.1
@@ -44,7 +48,7 @@
4448
* @see org.springframework.validation.beanvalidation.SpringValidatorAdapter
4549
* @see org.springframework.validation.beanvalidation.MethodValidationPostProcessor
4650
*/
47-
@Target({ElementType.TYPE, ElementType.PARAMETER})
51+
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
4852
@Retention(RetentionPolicy.RUNTIME)
4953
@Documented
5054
public @interface Validated {

spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,11 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
141141
* @return the applicable validation groups as a Class array
142142
*/
143143
protected Class<?>[] determineValidationGroups(MethodInvocation invocation) {
144-
Validated valid = AnnotationUtils.findAnnotation(invocation.getThis().getClass(), Validated.class);
145-
return (valid != null ? valid.value() : new Class<?>[0]);
144+
Validated validatedAnn = AnnotationUtils.findAnnotation(invocation.getMethod(), Validated.class);
145+
if (validatedAnn == null) {
146+
validatedAnn = AnnotationUtils.findAnnotation(invocation.getThis().getClass(), Validated.class);
147+
}
148+
return (validatedAnn != null ? validatedAnn.value() : new Class<?>[0]);
146149
}
147150

148151

spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,17 +124,28 @@ public interface MyValidInterface {
124124

125125
@NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);
126126

127-
@Async void myValidAsyncMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);
127+
@MyValid
128+
@Async void myValidAsyncMethod(@NotNull(groups = OtherGroup.class) String arg1, @Max(10) int arg2);
128129
}
129130

130131

131132
public interface MyGroup {
132133
}
133134

134135

136+
public interface OtherGroup {
137+
}
138+
139+
135140
@Validated({MyGroup.class, Default.class})
136141
@Retention(RetentionPolicy.RUNTIME)
137142
public @interface MyStereotype {
138143
}
139144

145+
146+
@Validated({OtherGroup.class, Default.class})
147+
@Retention(RetentionPolicy.RUNTIME)
148+
public @interface MyValid {
149+
}
150+
140151
}

0 commit comments

Comments
 (0)