Skip to content

Commit

Permalink
Align cascading of config prop validation with bean validation spec
Browse files Browse the repository at this point in the history
Closes gh-40345
  • Loading branch information
wilkinsona committed Jun 21, 2024
1 parent d9e9a46 commit 7701201
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

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:

include-code::nested/MyProperties[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ class ConfigurationPropertiesBinder {

private final boolean jsr303Present;

private volatile Validator jsr303Validator;

private volatile Binder binder;

ConfigurationPropertiesBinder(ApplicationContext applicationContext) {
Expand Down Expand Up @@ -141,7 +139,7 @@ private List<Validator> getValidators(Bindable<?> target) {
validators.add(this.configurationPropertiesValidator);
}
if (this.jsr303Present && target.getAnnotation(Validated.class) != null) {
validators.add(getJsr303Validator());
validators.add(getJsr303Validator(target.getType().resolve()));
}
Validator selfValidator = getSelfValidator(target);
if (selfValidator != null) {
Expand All @@ -162,11 +160,8 @@ private Validator getSelfValidator(Bindable<?> target) {
return null;
}

private Validator getJsr303Validator() {
if (this.jsr303Validator == null) {
this.jsr303Validator = new ConfigurationPropertiesJsr303Validator(this.applicationContext);
}
return this.jsr303Validator;
private Validator getJsr303Validator(Class<?> type) {
return new ConfigurationPropertiesJsr303Validator(this.applicationContext, type);
}

private List<ConfigurationPropertiesBindHandlerAdvisor> getBindHandlerAdvisors() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@ final class ConfigurationPropertiesJsr303Validator implements Validator {

private final Delegate delegate;

ConfigurationPropertiesJsr303Validator(ApplicationContext applicationContext) {
private final Class<?> validatedType;

ConfigurationPropertiesJsr303Validator(ApplicationContext applicationContext, Class<?> validatedType) {
this.delegate = new Delegate(applicationContext);
this.validatedType = validatedType;
}

@Override
public boolean supports(Class<?> type) {
return this.delegate.supports(type);
return this.validatedType.equals(type) && this.delegate.supports(type);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
import static org.assertj.core.api.Assertions.assertThatException;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
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.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
Expand Down Expand Up @@ -525,10 +526,9 @@ void loadValidatedOnBeanMethodAndJsr303ConstraintDoesNotMatchShouldFail() {
}

@Test
void loadWhenJsr303ConstraintDoesNotMatchOnNestedThatIsNotDirectlyAnnotatedShouldFail() {
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
.isThrownBy(() -> load(ValidatedNestedJsr303Properties.class, "properties.description="))
.withCauseInstanceOf(BindException.class);
void loadWhenJsr303ConstraintDoesNotMatchOnNestedThatIsNotAnnotatedWithValidShouldNotFail() {
assertThatNoException()
.isThrownBy(() -> load(ValidatedNestedJsr303Properties.class, "properties.description="));
}

@Test
Expand Down Expand Up @@ -1837,7 +1837,7 @@ static class NonValidatedJsr303Properties extends Jsr303Properties {
@Validated
static class ValidatedNestedJsr303Properties {

private Jsr303Properties properties;
private final Jsr303Properties properties = new Jsr303Properties();

Jsr303Properties getProperties() {
return this.properties;
Expand All @@ -1851,9 +1851,9 @@ Jsr303Properties getProperties() {
static class ValidatedValidNestedJsr303Properties {

@Valid
private final List<Jsr303Properties> properties = Collections.singletonList(new Jsr303Properties());
private final Jsr303Properties properties = new Jsr303Properties();

List<Jsr303Properties> getProperties() {
Jsr303Properties getProperties() {
return this.properties;
}

Expand Down

0 comments on commit 7701201

Please sign in to comment.