Skip to content

Commit 976b4f3

Browse files
imvtslrstoyanchev
authored andcommitted
Fix return value validation
Fix argument in call to applyReturnValueValidation() method in MethodValidationInterceptor.java. Method argument was passed instead of the return value of the method that was being validated. See gh-33105
1 parent 100da83 commit 976b4f3

File tree

2 files changed

+81
-12
lines changed

2 files changed

+81
-12
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
174174
Object returnValue = invocation.proceed();
175175

176176
if (this.adaptViolations) {
177-
this.validationAdapter.applyReturnValueValidation(target, method, null, arguments, groups);
177+
this.validationAdapter.applyReturnValueValidation(target, method, null, returnValue, groups);
178178
}
179179
else {
180180
violations = this.validationAdapter.invokeValidatorForReturnValue(target, method, returnValue, groups);

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

+80-11
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import java.lang.annotation.RetentionPolicy;
2121
import java.lang.reflect.Method;
2222

23-
import jakarta.validation.ValidationException;
23+
import jakarta.validation.ConstraintViolationException;
24+
import jakarta.validation.Validation;
2425
import jakarta.validation.Validator;
26+
import jakarta.validation.ValidatorFactory;
2527
import jakarta.validation.constraints.Max;
2628
import jakarta.validation.constraints.NotNull;
2729
import jakarta.validation.groups.Default;
@@ -45,7 +47,9 @@
4547
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
4648
import org.springframework.util.ClassUtils;
4749
import org.springframework.util.ReflectionUtils;
50+
import org.springframework.util.function.SingletonSupplier;
4851
import org.springframework.validation.annotation.Validated;
52+
import org.springframework.validation.method.MethodValidationException;
4953

5054
import static org.assertj.core.api.Assertions.assertThat;
5155
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -66,7 +70,19 @@ public void testMethodValidationInterceptor() {
6670
ProxyFactory factory = new ProxyFactory(bean);
6771
factory.addAdvice(new MethodValidationInterceptor());
6872
factory.addAdvisor(new AsyncAnnotationAdvisor());
69-
doTestProxyValidation((MyValidInterface<String>) factory.getProxy());
73+
doTestProxyValidation((MyValidInterface<String>) factory.getProxy(), ConstraintViolationException.class);
74+
}
75+
76+
@Test
77+
@SuppressWarnings("unchecked")
78+
public void testMethodValidationInterceptorWithAdaptConstraintViolations() {
79+
MyValidBean bean = new MyValidBean();
80+
ProxyFactory factory = new ProxyFactory(bean);
81+
try (ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory()) {
82+
factory.addAdvice(new MethodValidationInterceptor(SingletonSupplier.of(validatorFactory.getValidator()), true));
83+
factory.addAdvisor(new AsyncAnnotationAdvisor());
84+
doTestProxyValidation((MyValidInterface<String>) factory.getProxy(), MethodValidationException.class);
85+
}
7086
}
7187

7288
@Test
@@ -79,7 +95,26 @@ public void testMethodValidationPostProcessor() {
7995
context.registerSingleton("aapp", AsyncAnnotationBeanPostProcessor.class, pvs);
8096
context.registerSingleton("bean", MyValidBean.class);
8197
context.refresh();
82-
doTestProxyValidation(context.getBean("bean", MyValidInterface.class));
98+
doTestProxyValidation(context.getBean("bean", MyValidInterface.class), ConstraintViolationException.class);
99+
context.close();
100+
}
101+
102+
@Test
103+
@SuppressWarnings("unchecked")
104+
public void testMethodValidationPostProcessorWithAdaptConstraintViolations() {
105+
StaticApplicationContext context = new StaticApplicationContext();
106+
context.registerBean(MethodValidationPostProcessor.class, () -> {
107+
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
108+
postProcessor.setAdaptConstraintViolations(true);
109+
return postProcessor;
110+
});
111+
112+
MutablePropertyValues pvs = new MutablePropertyValues();
113+
pvs.add("beforeExistingAdvisors", false);
114+
context.registerSingleton("aapp", AsyncAnnotationBeanPostProcessor.class, pvs);
115+
context.registerSingleton("bean", MyValidBean.class);
116+
context.refresh();
117+
doTestProxyValidation(context.getBean("bean", MyValidInterface.class), MethodValidationException.class);
83118
context.close();
84119
}
85120

@@ -90,21 +125,38 @@ public void testMethodValidationPostProcessorForInterfaceOnlyProxy() {
90125
context.registerBean(MyValidInterface.class, () ->
91126
ProxyFactory.getProxy(MyValidInterface.class, new MyValidClientInterfaceMethodInterceptor()));
92127
context.refresh();
93-
doTestProxyValidation(context.getBean(MyValidInterface.class));
128+
doTestProxyValidation(context.getBean(MyValidInterface.class), ConstraintViolationException.class);
129+
context.close();
130+
}
131+
132+
@Test
133+
@SuppressWarnings("unchecked")
134+
public void testMethodValidationPostProcessorForInterfaceOnlyProxyWithAdaptConstraintViolations() {
135+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
136+
context.registerBean(MethodValidationPostProcessor.class, () -> {
137+
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
138+
postProcessor.setAdaptConstraintViolations(true);
139+
return postProcessor;
140+
});
141+
142+
context.registerBean(MyValidInterface.class, () ->
143+
ProxyFactory.getProxy(MyValidInterface.class, new MyValidClientInterfaceMethodInterceptor()));
144+
context.refresh();
145+
doTestProxyValidation(context.getBean(MyValidInterface.class), MethodValidationException.class);
94146
context.close();
95147
}
96148

97149
@SuppressWarnings("DataFlowIssue")
98-
private void doTestProxyValidation(MyValidInterface<String> proxy) {
150+
private void doTestProxyValidation(MyValidInterface<String> proxy, Class<? extends Exception> expectedExceptionClass) {
99151
assertThat(proxy.myValidMethod("value", 5)).isNotNull();
100-
assertThatExceptionOfType(ValidationException.class).isThrownBy(() -> proxy.myValidMethod("value", 15));
101-
assertThatExceptionOfType(ValidationException.class).isThrownBy(() -> proxy.myValidMethod(null, 5));
102-
assertThatExceptionOfType(ValidationException.class).isThrownBy(() -> proxy.myValidMethod("value", 0));
152+
assertThatExceptionOfType(expectedExceptionClass).isThrownBy(() -> proxy.myValidMethod("value", 15));
153+
assertThatExceptionOfType(expectedExceptionClass).isThrownBy(() -> proxy.myValidMethod(null, 5));
154+
assertThatExceptionOfType(expectedExceptionClass).isThrownBy(() -> proxy.myValidMethod("value", 0));
103155
proxy.myValidAsyncMethod("value", 5);
104-
assertThatExceptionOfType(ValidationException.class).isThrownBy(() -> proxy.myValidAsyncMethod("value", 15));
105-
assertThatExceptionOfType(ValidationException.class).isThrownBy(() -> proxy.myValidAsyncMethod(null, 5));
156+
assertThatExceptionOfType(expectedExceptionClass).isThrownBy(() -> proxy.myValidAsyncMethod("value", 15));
157+
assertThatExceptionOfType(expectedExceptionClass).isThrownBy(() -> proxy.myValidAsyncMethod(null, 5));
106158
assertThat(proxy.myGenericMethod("myValue")).isEqualTo("myValue");
107-
assertThatExceptionOfType(ValidationException.class).isThrownBy(() -> proxy.myGenericMethod(null));
159+
assertThatExceptionOfType(expectedExceptionClass).isThrownBy(() -> proxy.myGenericMethod(null));
108160
}
109161

110162
@Test
@@ -122,6 +174,11 @@ void testLazyValidatorForMethodValidationWithValidatorProvider() {
122174
doTestLazyValidatorForMethodValidation(LazyMethodValidationConfigWithValidatorProvider.class);
123175
}
124176

177+
@Test
178+
void testLazyValidatorForMethodValidationWithAdaptConstraintViolations() {
179+
doTestLazyValidatorForMethodValidation(LazyMethodValidationConfigWithAdaptConstraintViolations.class);
180+
}
181+
125182
private void doTestLazyValidatorForMethodValidation(Class<?> configClass) {
126183
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
127184
context.register(configClass, CustomValidatorBean.class, MyValidBean.class, MyValidFactoryBean.class);
@@ -278,4 +335,16 @@ public static MethodValidationPostProcessor methodValidationPostProcessor(Object
278335
}
279336
}
280337

338+
@Configuration
339+
public static class LazyMethodValidationConfigWithAdaptConstraintViolations {
340+
341+
@Bean
342+
public static MethodValidationPostProcessor methodValidationPostProcessor(ObjectProvider<Validator> validator) {
343+
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
344+
postProcessor.setValidatorProvider(validator);
345+
postProcessor.setAdaptConstraintViolations(true);
346+
return postProcessor;
347+
}
348+
}
349+
281350
}

0 commit comments

Comments
 (0)