Skip to content

Commit 10f0017

Browse files
committed
Fix method validation in child contexts
Bean post-processors only apply to the context in which they're registered. ValidationAutoConfiguration will only auto-configure the MethodValidationPostProcessor if the post-processor is missing from the current context and any of its ancestors. If an ancestor context contains the post-processor it will not be auto-configured and the descendant context will not have method validation configured. This commit updates the auto-configuration to limit the search for an existing MethodValidationPostProcessor bean to the current context. Fixes gh-27890
1 parent a8eed97 commit 10f0017

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 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.
@@ -25,6 +25,7 @@
2525
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2626
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2727
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
28+
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
2829
import org.springframework.boot.validation.MessageInterpolatorFactory;
2930
import org.springframework.boot.validation.beanvalidation.FilteredMethodValidationPostProcessor;
3031
import org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;
@@ -62,7 +63,7 @@ public static LocalValidatorFactoryBean defaultValidator() {
6263
}
6364

6465
@Bean
65-
@ConditionalOnMissingBean
66+
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
6667
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
6768
@Lazy Validator validator, ObjectProvider<MethodValidationExcludeFilter> excludeFilters) {
6869
FilteredMethodValidationPostProcessor processor = new FilteredMethodValidationPostProcessor(

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
3535
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3636
import org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;
37-
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3837
import org.springframework.context.annotation.Bean;
3938
import org.springframework.context.annotation.Configuration;
4039
import org.springframework.context.annotation.Primary;
@@ -58,9 +57,8 @@
5857
*/
5958
class ValidationAutoConfigurationTests {
6059

61-
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(
62-
AnnotationConfigApplicationContext::new)
63-
.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class));
60+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
61+
.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class));
6462

6563
@Test
6664
void validationAutoConfigurationShouldConfigureDefaultValidator() {
@@ -224,6 +222,20 @@ void methodValidationPostProcessorValidatorDependencyDoesNotTriggerEarlyInitiali
224222
.contains("someService"));
225223
}
226224

225+
@Test
226+
void validationIsEnabledInChildContext() {
227+
this.contextRunner.run((parent) -> new ApplicationContextRunner()
228+
.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))
229+
.withUserConfiguration(SampleService.class).withParent(parent).run((context) -> {
230+
assertThat(context.getBeansOfType(Validator.class)).hasSize(0);
231+
assertThat(parent.getBeansOfType(Validator.class)).hasSize(1);
232+
SampleService service = context.getBean(SampleService.class);
233+
service.doSomething("Valid");
234+
assertThatExceptionOfType(ConstraintViolationException.class)
235+
.isThrownBy(() -> service.doSomething("KO"));
236+
}));
237+
}
238+
227239
private boolean isPrimaryBean(AssertableApplicationContext context, String beanName) {
228240
return ((BeanDefinitionRegistry) context.getSourceApplicationContext()).getBeanDefinition(beanName).isPrimary();
229241
}

0 commit comments

Comments
 (0)