Skip to content
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

@ConfigurationProperties class's default values are not visible in the Errors instance passed to Validator.validate(Object target, Errors errors) #25356

Closed
cdprete opened this issue Feb 18, 2021 · 6 comments
Assignees
Labels
type: regression A regression from a previous release
Milestone

Comments

@cdprete
Copy link

cdprete commented Feb 18, 2021

Spring Boot version: 2.4.3-SNAPSHOT

Hi.
I've a @ConfigurationProperties annotated class which implements the Validator interface to validate some fields, but the method in the subject is never called causing the validation to fail.
In particular, I've the following structure:

public class SecurityRequestExtractionProperties {

    private CookieExtractionNames cookie = new CookieExtractionNames();
    private HeaderExtractionNames header = new HeaderExtractionNames();

    // getters and setters here

    public static class CookieExtractionNames {

        private String requestId = "My-Request-ID";
        private String sessionId = "My-Session-ID";

        // getters and setters here
    }

    public static class HeaderExtractionNames {
        private String requestId = "My-Request-ID";
        private String sessionId = "My-Session-ID";
        private String tenant = "My-Tenant";

        // getters and setters here
    }

}

and

@ConfigurationProperties(prefix = SpringSecurityRequestExtractionProperties.PREFIX)
public class SpringSecurityRequestExtractionProperties
        extends SecurityRequestExtractionProperties implements Validator {

    public static final String PREFIX = "acme.security.request.extraction";

    @Override
    public boolean supports(Class<?> clazz) {
        return clazz == SpringSecurityRequestExtractionProperties.class;
    }

    @Override
    public void validate(Object target, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors, "cookie", "cookie.empty");
    }

}

In Spring Boot 2.1.2 the default values specified in the class where used when no value was explicitly configured, but in the specified version the validation actually fails with

Caused by: org.springframework.boot.context.properties.bind.validation.BindValidationException: Binding validation errors on acme.security.request.extraction
   - Field error in object 'acme.security.request.extraction' on field 'cookie': rejected value [null]; codes [cookie.empty.acme.security.request.extraction.cookie,cookie.empty.cookie,cookie.empty.acme.commons.security.api.SecurityRequestExtractionProperties$CookieExtractionNames,cookie.empty]; arguments []; default message [null]
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Feb 18, 2021
@wilkinsona
Copy link
Member

wilkinsona commented Feb 18, 2021

Thanks for the report, but I'm not sure what you're trying to do. A @ConfigurationProperties class shouldn't be a Validator. A Validator is a general-purpose contract for performing validation and isn't specific to any individual @ConfigurationProperties class. If you want to provide a validator for the validation of @ConfigurationProperties beans then, as described in the documentation, you should define a bean named configurationPropertiesValidator.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Feb 18, 2021
@cdprete
Copy link
Author

cdprete commented Feb 18, 2021

I've read that documentation and we're actually migrating our code from Spring Boot 2.1.2 to 2.4.3 and, as already said, before this was working fine (and nicer than having a single configurationPropertiesValidator bean 'cause the validation was encapsulated).

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Feb 18, 2021
@wilkinsona
Copy link
Member

Unfortunately, if your arrangement worked in 2.1.2 then I believe that was by accident rather than design. The documentation for 2.1.2 describes the same approach using a configurationPropertiesValidator bean.

@cdprete
Copy link
Author

cdprete commented Feb 18, 2021

How can you have multiple validators then? It seems impossible to me then.

@wilkinsona
Copy link
Member

Sorry, I was mistaken above. I'd forgotten that we'd added support for a @ConfigurationProperties bean itself being a Validator.

The change in behaviour appears to be a side-effect of the fix for #17424. BeanPropertyBindingResult will extract a value from the underlying target whereas ValidationResult will not. This means that the latter can only see values that have been bound while the former can also see default values.

ValidationBindHandler#onSuccess is a red herring here as it's only called when a property's been bound. That will never happen when relying purely on default values.

@wilkinsona wilkinsona added type: regression A regression from a previous release and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged labels Feb 18, 2021
@wilkinsona wilkinsona added this to the 2.3.x milestone Feb 18, 2021
@cdprete
Copy link
Author

cdprete commented Feb 18, 2021

I've just followed the flow from ValidationUtils.rejectIfEmpty and ended up in ValidationBindHandler :)

@wilkinsona wilkinsona changed the title ValidationBindHandler#onSuccess is never called @ConfigurationProperties class's default values are not visible in the Errors instance passed to Validator.validate(Object target, Errors errors) Feb 19, 2021
@wilkinsona wilkinsona changed the title @ConfigurationProperties class's default values are not visible in the Errors instance passed to Validator.validate(Object target, Errors errors) @ConfigurationProperties class's default values are not visible in the Errors instance passed to Validator.validate(Object target, Errors errors) Feb 19, 2021
@mbhave mbhave self-assigned this Mar 4, 2021
@mbhave mbhave closed this as completed in df1d1db Mar 12, 2021
@mbhave mbhave modified the milestones: 2.3.x, 2.3.10 Mar 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: regression A regression from a previous release
Projects
None yet
Development

No branches or pull requests

4 participants