Merge branch '2.4.x'

Closes gh-25862
pull/25873/head
Andy Wilkinson 4 years ago
commit 6a7de18101

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,12 +24,14 @@ import javax.validation.Validator;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfigurationTests.CustomValidatorConfiguration.TestBeanPostProcessor;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
@ -55,171 +57,143 @@ import static org.mockito.Mockito.mock;
*/
class ValidationAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@AfterEach
void close() {
if (this.context != null) {
this.context.close();
}
}
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(
AnnotationConfigApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class));
@Test
void validationAutoConfigurationShouldConfigureDefaultValidator() {
load(Config.class);
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
String[] springValidatorNames = this.context
.getBeanNamesForType(org.springframework.validation.Validator.class);
assertThat(jsrValidatorNames).containsExactly("defaultValidator");
assertThat(springValidatorNames).containsExactly("defaultValidator");
Validator jsrValidator = this.context.getBean(Validator.class);
org.springframework.validation.Validator springValidator = this.context
.getBean(org.springframework.validation.Validator.class);
assertThat(jsrValidator).isInstanceOf(LocalValidatorFactoryBean.class);
assertThat(jsrValidator).isEqualTo(springValidator);
assertThat(isPrimaryBean("defaultValidator")).isTrue();
this.contextRunner.run((context) -> {
assertThat(context.getBeanNamesForType(Validator.class)).containsExactly("defaultValidator");
assertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))
.containsExactly("defaultValidator");
assertThat(context.getBean(Validator.class)).isInstanceOf(LocalValidatorFactoryBean.class)
.isEqualTo(context.getBean(org.springframework.validation.Validator.class));
assertThat(isPrimaryBean(context, "defaultValidator")).isTrue();
});
}
@Test
void validationAutoConfigurationWhenUserProvidesValidatorShouldBackOff() {
load(UserDefinedValidatorConfig.class);
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
String[] springValidatorNames = this.context
.getBeanNamesForType(org.springframework.validation.Validator.class);
assertThat(jsrValidatorNames).containsExactly("customValidator");
assertThat(springValidatorNames).containsExactly("customValidator");
org.springframework.validation.Validator springValidator = this.context
.getBean(org.springframework.validation.Validator.class);
Validator jsrValidator = this.context.getBean(Validator.class);
assertThat(jsrValidator).isInstanceOf(OptionalValidatorFactoryBean.class);
assertThat(jsrValidator).isEqualTo(springValidator);
assertThat(isPrimaryBean("customValidator")).isFalse();
this.contextRunner.withUserConfiguration(UserDefinedValidatorConfig.class).run((context) -> {
assertThat(context.getBeanNamesForType(Validator.class)).containsExactly("customValidator");
assertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))
.containsExactly("customValidator");
assertThat(context.getBean(Validator.class)).isInstanceOf(OptionalValidatorFactoryBean.class)
.isEqualTo(context.getBean(org.springframework.validation.Validator.class));
assertThat(isPrimaryBean(context, "customValidator")).isFalse();
});
}
@Test
void validationAutoConfigurationWhenUserProvidesDefaultValidatorShouldNotEnablePrimary() {
load(UserDefinedDefaultValidatorConfig.class);
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
String[] springValidatorNames = this.context
.getBeanNamesForType(org.springframework.validation.Validator.class);
assertThat(jsrValidatorNames).containsExactly("defaultValidator");
assertThat(springValidatorNames).containsExactly("defaultValidator");
assertThat(isPrimaryBean("defaultValidator")).isFalse();
this.contextRunner.withUserConfiguration(UserDefinedDefaultValidatorConfig.class).run((context) -> {
assertThat(context.getBeanNamesForType(Validator.class)).containsExactly("defaultValidator");
assertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))
.containsExactly("defaultValidator");
assertThat(isPrimaryBean(context, "defaultValidator")).isFalse();
});
}
@Test
void validationAutoConfigurationWhenUserProvidesJsrValidatorShouldBackOff() {
load(UserDefinedJsrValidatorConfig.class);
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
String[] springValidatorNames = this.context
.getBeanNamesForType(org.springframework.validation.Validator.class);
assertThat(jsrValidatorNames).containsExactly("customValidator");
assertThat(springValidatorNames).isEmpty();
assertThat(isPrimaryBean("customValidator")).isFalse();
this.contextRunner.withUserConfiguration(UserDefinedJsrValidatorConfig.class).run((context) -> {
assertThat(context.getBeanNamesForType(Validator.class)).containsExactly("customValidator");
assertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class)).isEmpty();
assertThat(isPrimaryBean(context, "customValidator")).isFalse();
});
}
@Test
void validationAutoConfigurationWhenUserProvidesSpringValidatorShouldCreateJsrValidator() {
load(UserDefinedSpringValidatorConfig.class);
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
String[] springValidatorNames = this.context
.getBeanNamesForType(org.springframework.validation.Validator.class);
assertThat(jsrValidatorNames).containsExactly("defaultValidator");
assertThat(springValidatorNames).containsExactly("customValidator", "anotherCustomValidator",
"defaultValidator");
Validator jsrValidator = this.context.getBean(Validator.class);
org.springframework.validation.Validator springValidator = this.context
.getBean(org.springframework.validation.Validator.class);
assertThat(jsrValidator).isInstanceOf(LocalValidatorFactoryBean.class);
assertThat(jsrValidator).isEqualTo(springValidator);
assertThat(isPrimaryBean("defaultValidator")).isTrue();
this.contextRunner.withUserConfiguration(UserDefinedSpringValidatorConfig.class).run((context) -> {
assertThat(context.getBeanNamesForType(Validator.class)).containsExactly("defaultValidator");
assertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))
.containsExactly("customValidator", "anotherCustomValidator", "defaultValidator");
assertThat(context.getBean(Validator.class)).isInstanceOf(LocalValidatorFactoryBean.class)
.isEqualTo(context.getBean(org.springframework.validation.Validator.class));
assertThat(isPrimaryBean(context, "defaultValidator")).isTrue();
});
}
@Test
void validationAutoConfigurationWhenUserProvidesPrimarySpringValidatorShouldRemovePrimaryFlag() {
load(UserDefinedPrimarySpringValidatorConfig.class);
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
String[] springValidatorNames = this.context
.getBeanNamesForType(org.springframework.validation.Validator.class);
assertThat(jsrValidatorNames).containsExactly("defaultValidator");
assertThat(springValidatorNames).containsExactly("customValidator", "anotherCustomValidator",
"defaultValidator");
Validator jsrValidator = this.context.getBean(Validator.class);
org.springframework.validation.Validator springValidator = this.context
.getBean(org.springframework.validation.Validator.class);
assertThat(jsrValidator).isInstanceOf(LocalValidatorFactoryBean.class);
assertThat(springValidator).isEqualTo(this.context.getBean("anotherCustomValidator"));
assertThat(isPrimaryBean("defaultValidator")).isFalse();
this.contextRunner.withUserConfiguration(UserDefinedPrimarySpringValidatorConfig.class).run((context) -> {
assertThat(context.getBeanNamesForType(Validator.class)).containsExactly("defaultValidator");
assertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))
.containsExactly("customValidator", "anotherCustomValidator", "defaultValidator");
assertThat(context.getBean(Validator.class)).isInstanceOf(LocalValidatorFactoryBean.class);
assertThat(context.getBean(org.springframework.validation.Validator.class))
.isEqualTo(context.getBean("anotherCustomValidator"));
assertThat(isPrimaryBean(context, "defaultValidator")).isFalse();
});
}
@Test
void validationIsEnabled() {
load(SampleService.class);
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
SampleService service = this.context.getBean(SampleService.class);
this.contextRunner.withUserConfiguration(SampleService.class).run((context) -> {
assertThat(context.getBeansOfType(Validator.class)).hasSize(1);
SampleService service = context.getBean(SampleService.class);
service.doSomething("Valid");
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething("KO"));
});
}
@Test
void classCanBeExcludedFromValidation() {
load(ExcludedServiceConfiguration.class);
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
ExcludedService service = this.context.getBean(ExcludedService.class);
this.contextRunner.withUserConfiguration(ExcludedServiceConfiguration.class).run((context) -> {
assertThat(context.getBeansOfType(Validator.class)).hasSize(1);
ExcludedService service = context.getBean(ExcludedService.class);
service.doSomething("Valid");
assertThatNoException().isThrownBy(() -> service.doSomething("KO"));
});
}
@Test
void validationUsesCglibProxy() {
load(DefaultAnotherSampleService.class);
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
DefaultAnotherSampleService service = this.context.getBean(DefaultAnotherSampleService.class);
this.contextRunner.withUserConfiguration(DefaultAnotherSampleService.class).run((context) -> {
assertThat(context.getBeansOfType(Validator.class)).hasSize(1);
DefaultAnotherSampleService service = context.getBean(DefaultAnotherSampleService.class);
service.doSomething(42);
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething(2));
});
}
@Test
void validationCanBeConfiguredToUseJdkProxy() {
load(AnotherSampleServiceConfiguration.class, "spring.aop.proxy-target-class=false");
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
assertThat(this.context.getBeansOfType(DefaultAnotherSampleService.class)).isEmpty();
AnotherSampleService service = this.context.getBean(AnotherSampleService.class);
this.contextRunner.withUserConfiguration(AnotherSampleServiceConfiguration.class)
.withPropertyValues("spring.aop.proxy-target-class=false").run((context) -> {
assertThat(context.getBeansOfType(Validator.class)).hasSize(1);
assertThat(context.getBeansOfType(DefaultAnotherSampleService.class)).isEmpty();
AnotherSampleService service = context.getBean(AnotherSampleService.class);
service.doSomething(42);
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething(2));
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> service.doSomething(2));
});
}
@Test
void userDefinedMethodValidationPostProcessorTakesPrecedence() {
load(SampleConfiguration.class);
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
Object userMethodValidationPostProcessor = this.context.getBean("testMethodValidationPostProcessor");
assertThat(this.context.getBean(MethodValidationPostProcessor.class))
this.contextRunner.withUserConfiguration(SampleConfiguration.class).run((context) -> {
assertThat(context.getBeansOfType(Validator.class)).hasSize(1);
Object userMethodValidationPostProcessor = context.getBean("testMethodValidationPostProcessor");
assertThat(context.getBean(MethodValidationPostProcessor.class))
.isSameAs(userMethodValidationPostProcessor);
assertThat(this.context.getBeansOfType(MethodValidationPostProcessor.class)).hasSize(1);
assertThat(this.context.getBean(Validator.class))
assertThat(context.getBeansOfType(MethodValidationPostProcessor.class)).hasSize(1);
assertThat(context.getBean(Validator.class))
.isNotSameAs(ReflectionTestUtils.getField(userMethodValidationPostProcessor, "validator"));
});
}
@Test
void methodValidationPostProcessorValidatorDependencyDoesNotTriggerEarlyInitialization() {
load(CustomValidatorConfiguration.class);
assertThat(this.context.getBean(TestBeanPostProcessor.class).postProcessed).contains("someService");
this.contextRunner.withUserConfiguration(CustomValidatorConfiguration.class)
.run((context) -> assertThat(context.getBean(TestBeanPostProcessor.class).postProcessed)
.contains("someService"));
}
private boolean isPrimaryBean(String beanName) {
return this.context.getBeanDefinition(beanName).isPrimary();
}
private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
TestPropertyValues.of(environment).applyTo(ctx);
if (config != null) {
ctx.register(config);
}
ctx.register(ValidationAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
private boolean isPrimaryBean(AssertableApplicationContext context, String beanName) {
return ((BeanDefinitionRegistry) context.getSourceApplicationContext()).getBeanDefinition(beanName).isPrimary();
}
@Configuration(proxyBeanMethods = false)

Loading…
Cancel
Save