mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-15 01:07:30 +08:00
Align cascading of config prop validation with bean validation spec
Closes gh-40345
This commit is contained in:
parent
d9e9a46189
commit
7701201bc3
@ -1178,7 +1178,7 @@ include-code::MyProperties[]
|
|||||||
|
|
||||||
TIP: You can also trigger validation by annotating the `@Bean` method that creates the configuration properties with `@Validated`.
|
TIP: You can also trigger validation by annotating the `@Bean` method that creates the configuration properties with `@Validated`.
|
||||||
|
|
||||||
To ensure that validation is always triggered for nested properties, even when no properties are found, the associated field must be annotated with `@Valid`.
|
To cascade validation to nested properties the associated field must be annotated with `@Valid`.
|
||||||
The following example builds on the preceding `MyProperties` example:
|
The following example builds on the preceding `MyProperties` example:
|
||||||
|
|
||||||
include-code::nested/MyProperties[]
|
include-code::nested/MyProperties[]
|
||||||
|
@ -76,8 +76,6 @@ class ConfigurationPropertiesBinder {
|
|||||||
|
|
||||||
private final boolean jsr303Present;
|
private final boolean jsr303Present;
|
||||||
|
|
||||||
private volatile Validator jsr303Validator;
|
|
||||||
|
|
||||||
private volatile Binder binder;
|
private volatile Binder binder;
|
||||||
|
|
||||||
ConfigurationPropertiesBinder(ApplicationContext applicationContext) {
|
ConfigurationPropertiesBinder(ApplicationContext applicationContext) {
|
||||||
@ -141,7 +139,7 @@ class ConfigurationPropertiesBinder {
|
|||||||
validators.add(this.configurationPropertiesValidator);
|
validators.add(this.configurationPropertiesValidator);
|
||||||
}
|
}
|
||||||
if (this.jsr303Present && target.getAnnotation(Validated.class) != null) {
|
if (this.jsr303Present && target.getAnnotation(Validated.class) != null) {
|
||||||
validators.add(getJsr303Validator());
|
validators.add(getJsr303Validator(target.getType().resolve()));
|
||||||
}
|
}
|
||||||
Validator selfValidator = getSelfValidator(target);
|
Validator selfValidator = getSelfValidator(target);
|
||||||
if (selfValidator != null) {
|
if (selfValidator != null) {
|
||||||
@ -162,11 +160,8 @@ class ConfigurationPropertiesBinder {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Validator getJsr303Validator() {
|
private Validator getJsr303Validator(Class<?> type) {
|
||||||
if (this.jsr303Validator == null) {
|
return new ConfigurationPropertiesJsr303Validator(this.applicationContext, type);
|
||||||
this.jsr303Validator = new ConfigurationPropertiesJsr303Validator(this.applicationContext);
|
|
||||||
}
|
|
||||||
return this.jsr303Validator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ConfigurationPropertiesBindHandlerAdvisor> getBindHandlerAdvisors() {
|
private List<ConfigurationPropertiesBindHandlerAdvisor> getBindHandlerAdvisors() {
|
||||||
|
@ -37,13 +37,16 @@ final class ConfigurationPropertiesJsr303Validator implements Validator {
|
|||||||
|
|
||||||
private final Delegate delegate;
|
private final Delegate delegate;
|
||||||
|
|
||||||
ConfigurationPropertiesJsr303Validator(ApplicationContext applicationContext) {
|
private final Class<?> validatedType;
|
||||||
|
|
||||||
|
ConfigurationPropertiesJsr303Validator(ApplicationContext applicationContext, Class<?> validatedType) {
|
||||||
this.delegate = new Delegate(applicationContext);
|
this.delegate = new Delegate(applicationContext);
|
||||||
|
this.validatedType = validatedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(Class<?> type) {
|
public boolean supports(Class<?> type) {
|
||||||
return this.delegate.supports(type);
|
return this.validatedType.equals(type) && this.delegate.supports(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -106,6 +106,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
import static org.assertj.core.api.Assertions.assertThatException;
|
import static org.assertj.core.api.Assertions.assertThatException;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||||
import static org.assertj.core.api.Assertions.entry;
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
@ -525,10 +526,9 @@ class ConfigurationPropertiesTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadWhenJsr303ConstraintDoesNotMatchOnNestedThatIsNotDirectlyAnnotatedShouldFail() {
|
void loadWhenJsr303ConstraintDoesNotMatchOnNestedThatIsNotAnnotatedWithValidShouldNotFail() {
|
||||||
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
|
assertThatNoException()
|
||||||
.isThrownBy(() -> load(ValidatedNestedJsr303Properties.class, "properties.description="))
|
.isThrownBy(() -> load(ValidatedNestedJsr303Properties.class, "properties.description="));
|
||||||
.withCauseInstanceOf(BindException.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1837,7 +1837,7 @@ class ConfigurationPropertiesTests {
|
|||||||
@Validated
|
@Validated
|
||||||
static class ValidatedNestedJsr303Properties {
|
static class ValidatedNestedJsr303Properties {
|
||||||
|
|
||||||
private Jsr303Properties properties;
|
private final Jsr303Properties properties = new Jsr303Properties();
|
||||||
|
|
||||||
Jsr303Properties getProperties() {
|
Jsr303Properties getProperties() {
|
||||||
return this.properties;
|
return this.properties;
|
||||||
@ -1851,9 +1851,9 @@ class ConfigurationPropertiesTests {
|
|||||||
static class ValidatedValidNestedJsr303Properties {
|
static class ValidatedValidNestedJsr303Properties {
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
private final List<Jsr303Properties> properties = Collections.singletonList(new Jsr303Properties());
|
private final Jsr303Properties properties = new Jsr303Properties();
|
||||||
|
|
||||||
List<Jsr303Properties> getProperties() {
|
Jsr303Properties getProperties() {
|
||||||
return this.properties;
|
return this.properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user