17
17
package org .springframework .validation .beanvalidation ;
18
18
19
19
import java .lang .reflect .Method ;
20
- import java .util .Set ;
21
20
import java .util .function .Supplier ;
22
21
23
- import jakarta .validation .ConstraintViolation ;
24
- import jakarta .validation .ConstraintViolationException ;
25
- import jakarta .validation .Validation ;
26
22
import jakarta .validation .Validator ;
27
23
import jakarta .validation .ValidatorFactory ;
28
- import jakarta .validation .executable .ExecutableValidator ;
29
24
import org .aopalliance .intercept .MethodInterceptor ;
30
25
import org .aopalliance .intercept .MethodInvocation ;
31
26
32
27
import org .springframework .aop .ProxyMethodInvocation ;
33
- import org .springframework .aop .framework .AopProxyUtils ;
34
- import org .springframework .aop .support .AopUtils ;
35
28
import org .springframework .beans .factory .FactoryBean ;
36
29
import org .springframework .beans .factory .SmartFactoryBean ;
37
- import org .springframework .core .BridgeMethodResolver ;
38
- import org .springframework .core .annotation .AnnotationUtils ;
39
30
import org .springframework .lang .Nullable ;
40
31
import org .springframework .util .Assert ;
41
32
import org .springframework .util .ClassUtils ;
42
- import org .springframework .util .function .SingletonSupplier ;
43
33
import org .springframework .validation .annotation .Validated ;
44
34
45
35
/**
46
36
* An AOP Alliance {@link MethodInterceptor} implementation that delegates to a
47
37
* JSR-303 provider for performing method-level validation on annotated methods.
48
38
*
49
- * <p>Applicable methods have JSR-303 constraint annotations on their parameters
50
- * and/or on their return value (in the latter case specified at the method level,
51
- * typically as inline annotation).
39
+ * <p>Applicable methods have {@link jakarta.validation.Constraint} annotations on
40
+ * their parameters and/or on their return value (in the latter case specified at
41
+ * the method level, typically as inline annotation).
52
42
*
53
43
* <p>E.g.: {@code public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)}
54
44
*
65
55
*/
66
56
public class MethodValidationInterceptor implements MethodInterceptor {
67
57
68
- private final Supplier < Validator > validator ;
58
+ private final MethodValidationDelegate delegate ;
69
59
70
60
71
61
/**
72
62
* Create a new MethodValidationInterceptor using a default JSR-303 validator underneath.
73
63
*/
74
64
public MethodValidationInterceptor () {
75
- this .validator = SingletonSupplier . of (() -> Validation . buildDefaultValidatorFactory (). getValidator () );
65
+ this .delegate = new MethodValidationDelegate ( );
76
66
}
77
67
78
68
/**
79
69
* Create a new MethodValidationInterceptor using the given JSR-303 ValidatorFactory.
80
70
* @param validatorFactory the JSR-303 ValidatorFactory to use
81
71
*/
82
72
public MethodValidationInterceptor (ValidatorFactory validatorFactory ) {
83
- this .validator = SingletonSupplier . of (validatorFactory :: getValidator );
73
+ this .delegate = new MethodValidationDelegate (validatorFactory );
84
74
}
85
75
86
76
/**
87
77
* Create a new MethodValidationInterceptor using the given JSR-303 Validator.
88
78
* @param validator the JSR-303 Validator to use
89
79
*/
90
80
public MethodValidationInterceptor (Validator validator ) {
91
- this .validator = () -> validator ;
81
+ this .delegate = new MethodValidationDelegate ( validator ) ;
92
82
}
93
83
94
84
/**
@@ -98,7 +88,7 @@ public MethodValidationInterceptor(Validator validator) {
98
88
* @since 6.0
99
89
*/
100
90
public MethodValidationInterceptor (Supplier <Validator > validator ) {
101
- this .validator = validator ;
91
+ this .delegate = new MethodValidationDelegate ( validator ) ;
102
92
}
103
93
104
94
@@ -110,42 +100,25 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
110
100
return invocation .proceed ();
111
101
}
112
102
103
+ Object target = getTarget (invocation );
104
+ Method method = invocation .getMethod ();
113
105
Class <?>[] groups = determineValidationGroups (invocation );
106
+ this .delegate .validateMethodArguments (target , method , invocation .getArguments (), groups );
114
107
115
- // Standard Bean Validation 1.1 API
116
- ExecutableValidator execVal = this .validator .get ().forExecutables ();
117
- Method methodToValidate = invocation .getMethod ();
118
- Set <ConstraintViolation <Object >> result ;
108
+ Object returnValue = invocation .proceed ();
109
+
110
+ this .delegate .validateMethodReturnValue (target , method , returnValue , groups );
111
+ return returnValue ;
112
+ }
119
113
114
+ private static Object getTarget (MethodInvocation invocation ) {
120
115
Object target = invocation .getThis ();
121
116
if (target == null && invocation instanceof ProxyMethodInvocation methodInvocation ) {
122
117
// Allow validation for AOP proxy without a target
123
118
target = methodInvocation .getProxy ();
124
119
}
125
120
Assert .state (target != null , "Target must not be null" );
126
-
127
- try {
128
- result = execVal .validateParameters (target , methodToValidate , invocation .getArguments (), groups );
129
- }
130
- catch (IllegalArgumentException ex ) {
131
- // Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
132
- // Let's try to find the bridged method on the implementation class...
133
- methodToValidate = BridgeMethodResolver .findBridgedMethod (
134
- ClassUtils .getMostSpecificMethod (invocation .getMethod (), target .getClass ()));
135
- result = execVal .validateParameters (target , methodToValidate , invocation .getArguments (), groups );
136
- }
137
- if (!result .isEmpty ()) {
138
- throw new ConstraintViolationException (result );
139
- }
140
-
141
- Object returnValue = invocation .proceed ();
142
-
143
- result = execVal .validateReturnValue (target , methodToValidate , returnValue , groups );
144
- if (!result .isEmpty ()) {
145
- throw new ConstraintViolationException (result );
146
- }
147
-
148
- return returnValue ;
121
+ return target ;
149
122
}
150
123
151
124
private boolean isFactoryBeanMetadataMethod (Method method ) {
@@ -178,25 +151,9 @@ else if (FactoryBean.class.isAssignableFrom(clazz)) {
178
151
* @return the applicable validation groups as a Class array
179
152
*/
180
153
protected Class <?>[] determineValidationGroups (MethodInvocation invocation ) {
181
- Validated validatedAnn = AnnotationUtils .findAnnotation (invocation .getMethod (), Validated .class );
182
- if (validatedAnn == null ) {
183
- Object target = invocation .getThis ();
184
- if (target != null ) {
185
- validatedAnn = AnnotationUtils .findAnnotation (target .getClass (), Validated .class );
186
- }
187
- else if (invocation instanceof ProxyMethodInvocation methodInvocation ) {
188
- Object proxy = methodInvocation .getProxy ();
189
- if (AopUtils .isAopProxy (proxy )) {
190
- for (Class <?> type : AopProxyUtils .proxiedUserInterfaces (proxy )) {
191
- validatedAnn = AnnotationUtils .findAnnotation (type , Validated .class );
192
- if (validatedAnn != null ) {
193
- break ;
194
- }
195
- }
196
- }
197
- }
198
- }
199
- return (validatedAnn != null ? validatedAnn .value () : new Class <?>[0 ]);
154
+ Object target = getTarget (invocation );
155
+ Method method = invocation .getMethod ();
156
+ return this .delegate .determineValidationGroups (target , method );
200
157
}
201
158
202
159
}
0 commit comments