-
Notifications
You must be signed in to change notification settings - Fork 40.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Align cascade behavior of @Validated @ConfigurationProperties with the bean validation spec #40345
Comments
I think it's a bug that we propagate validation to fields which aren't annotated with |
@mhalbritter I'd be happy to contribute a fix for this, if you accept contributions and it's not too time-sensitive (in the next month). |
Thanks for the offer @LeMikaelF, but we first want to understand all the different ways how this works. Configuration property binding is a beast, with multiple ways how fields are bound to configuration properties (setters, constructor injection, etc.). We're also not sure in which version we should fix this, as the current behavior is there for a long time and this may fail users in a subtle way. |
This is to be expected. With no properties to bind to a Where a difference can be observed is when a property is bound to I've verified the current behavior back to 2.0 and things appear to have behaved as they do now since then. Given this, I think it's quite hard to justify changing this. I'm leaning towards documenting the current behavior more precisely. |
I'm now not so sure about just documenting this as I've noticed another problem with how we use When the binder encounters a constraint violation, it stops validating. This means that if you have constraints at different levels of the hierarchy, only the lowest down violations will be reported. Consider this example: package com.example.gh_40345;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import com.example.gh_40345.Gh40345Application.SomeProperties;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
@EnableConfigurationProperties(SomeProperties.class)
@SpringBootApplication
public class Gh40345Application {
public static void main(String[] args) {
SpringApplication.run(Gh40345Application.class, args);
}
@Validated
@ConfigurationProperties("some")
static class SomeProperties {
@Valid
private final Group group = new Group();
@NotNull
private String propertyOne;
public Group getGroup() {
return group;
}
public String getPropertyOne() {
return propertyOne;
}
public void setPropertyOne(String propertyOne) {
this.propertyOne = propertyOne;
}
static class Group {
@NotNull
private String propertyTwo;
private String propertyThree;
public String getPropertyTwo() {
return propertyTwo;
}
public void setPropertyTwo(String propertyTwo) {
this.propertyTwo = propertyTwo;
}
public String getPropertyThree() {
return propertyThree;
}
public void setPropertyThree(String propertyThree) {
this.propertyThree = propertyThree;
}
}
}
} If we run it with
A constraint is missing as the binder validates the Lines 140 to 142 in 84956ad
This prevents any further validation and the exception is thrown once we've reached the top of the hierarchy: Lines 109 to 120 in 84956ad
If we run it without any properties, we get both of the violations that we expected:
In this case, we've received both violations as they've been identified when validating the If we changed |
We discussed this today and we consider this a bug, but one that is too risky to attempt to fix in a patch release. We're going to try and take a look for the next minor. |
When a JSR 303 implementation is on the classpath, Spring Boot validates all Configuration Properties classes that are annotated with
@Validated
(seeConfigurationPropertiesBinder::getValidators
). But the validation applies to all nested objects, even if they're not annotated with@Valid
. This doesn't comply with the JSR 303 spec (see the notion of traversable properties) and can lead to some surprising results. For example, the bean below will fail validation given a single propertyprops.nested.myprop1=value
, even though the fieldprivate Nested nested
isn't annotated with@Valid
. Likewise, nested collections and maps will fail validation if they contain objects that are themselves annotated with jsr 303 annotations (ex:@NotEmpty
), even if validation isn't cascaded with an@Valid
. See this reproducer.The documentation is also somewhat confusing for this. It states:
But nested objects will not be validated if there are no properties to bind. For example, adding
@Valid
to theprivate Nested nested
field above will not result in a failure if there is noprops.nested.myprop1
property.I can think of two solutions:
@Valid
fields only.@Validated
.I personally prefer option 1, because it corresponds to behaviour that is expected from a JSR 303 validator.
The text was updated successfully, but these errors were encountered: