|
|
|
|
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
|
|
|
|
/* |
|
|
|
|
* Copyright 2012-2019 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;
@@ -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.context.annotation.AnnotationConfigApplicationContext; |
|
|
|
|
import org.springframework.context.annotation.Bean; |
|
|
|
|
import org.springframework.context.annotation.Configuration; |
|
|
|
|
@ -53,162 +55,133 @@ import static org.mockito.Mockito.mock;
@@ -53,162 +55,133 @@ 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); |
|
|
|
|
service.doSomething("Valid"); |
|
|
|
|
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething("KO")); |
|
|
|
|
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 validationUsesCglibProxy() { |
|
|
|
|
load(DefaultAnotherSampleService.class); |
|
|
|
|
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1); |
|
|
|
|
DefaultAnotherSampleService service = this.context.getBean(DefaultAnotherSampleService.class); |
|
|
|
|
service.doSomething(42); |
|
|
|
|
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething(2)); |
|
|
|
|
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); |
|
|
|
|
service.doSomething(42); |
|
|
|
|
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething(2)); |
|
|
|
|
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)); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@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)) |
|
|
|
|
.isSameAs(userMethodValidationPostProcessor); |
|
|
|
|
assertThat(this.context.getBeansOfType(MethodValidationPostProcessor.class)).hasSize(1); |
|
|
|
|
assertThat(this.context.getBean(Validator.class)) |
|
|
|
|
.isNotSameAs(ReflectionTestUtils.getField(userMethodValidationPostProcessor, "validator")); |
|
|
|
|
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(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) |
|
|
|
|
|