admin管理员组

文章数量:1122846

Situation

I am trying to create a autoconfiguration in which some properties must pass validation only in specific cases. I have a service MyService which requires credentials properties.username and properties.password, and a OncePerRequestFilter, which intercepts controller calls and calls MyService to perform some action, which requires the application's name properties.app-name.

Here is the global layout:

  • when I provide no property and no MyService bean exists, the autoconfiguration does nothing,
  • when no MyService bean exists, but I provide a username and password in the properties, I will create a new MyService bean, and I wish to validate the username and password,
  • when there exists a MyService bean, I will create a OncePerRequestFilter, and I wish to validate the application name.

In order to do so, I wanted to use validation groups. I already implemented some validation in configuration properties before, and therefore know that Spring checks them when instantiating the object, but I have never tried with groups.

First try

Code

Autoconfiguration

@AutoConfiguration
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "properties", name = { "username", "password" })
    @Validated(CredentialsRequired.class)
    public MyService myDefaultService(@Valid MyProperties properties) {
        return new MyService(properties);
    }

    @Bean
    @ConditionalOnBean(MyService.class)
    @Validated(AppNameRequired.class)
    OncePerRequestFilter myFilter(@Valid MyProperties properties, MyService myService) {
        return new MyFilter(properties, myService);
    }
}

Configuration properties

@Data
@ConfigurationProperties("properties")
public class MyProperties {
    @NotBlank(groups = AppNameRequired.class)
    private String appName;

    @NotBlank(groups = CredentialsRequired.class)
    private String username;

    @NotBlank(groups = CredentialsRequired.class)
    private String password;
}

Result

When I provide no property, nothing fails, which is desired. However, if I just use the following properties:

properties.username=
properties.password=

then both the service and the filter are created without any automatic validation issue, as this short modification shows:

@Bean
@ConditionalOnBean(MyService.class)
@Validated(AppNameRequired.class)
OncePerRequestFilter myFilter(@Valid MyProperties properties, MyService myService, Validator validator) {
    if(!validator.validate(properties, AppNameRequired.class).isEmpty()) {
        throw new IllegalArgumentException();  // Should not be reached if validation works, but is thrown on instantiation
    }

    return new MyFilter(properties, myService);
}

Trying with @Validated on properties class

I have also tried applying @Validated on MyProperties, but it did not change much. Furthermore, I noticed this in a more global case:

  • when there is @Validated on the class, and constraints without groups are all valid, no error is thrown, even if some constraints with groups are invalid
  • when there is @Validated on the class, but at least one constraint without group is violated, Spring fails the instantiation
  • when there is @Validated(AppNameRequired.class) on the class, and constraints without groups are all valid, no error is thrown, even if the constraints with group AppNameRequired are invalid

My conclusion, and my question

After all of this, my conclusion is that Spring does not support validation groups for bean validation. Hence, I wonder: is there a way to perform this conditional validation by relying on the Jakarta and Spring Boot annotations only, or am I forced to manually call a validator to perform this?

Situation

I am trying to create a autoconfiguration in which some properties must pass validation only in specific cases. I have a service MyService which requires credentials properties.username and properties.password, and a OncePerRequestFilter, which intercepts controller calls and calls MyService to perform some action, which requires the application's name properties.app-name.

Here is the global layout:

  • when I provide no property and no MyService bean exists, the autoconfiguration does nothing,
  • when no MyService bean exists, but I provide a username and password in the properties, I will create a new MyService bean, and I wish to validate the username and password,
  • when there exists a MyService bean, I will create a OncePerRequestFilter, and I wish to validate the application name.

In order to do so, I wanted to use validation groups. I already implemented some validation in configuration properties before, and therefore know that Spring checks them when instantiating the object, but I have never tried with groups.

First try

Code

Autoconfiguration

@AutoConfiguration
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "properties", name = { "username", "password" })
    @Validated(CredentialsRequired.class)
    public MyService myDefaultService(@Valid MyProperties properties) {
        return new MyService(properties);
    }

    @Bean
    @ConditionalOnBean(MyService.class)
    @Validated(AppNameRequired.class)
    OncePerRequestFilter myFilter(@Valid MyProperties properties, MyService myService) {
        return new MyFilter(properties, myService);
    }
}

Configuration properties

@Data
@ConfigurationProperties("properties")
public class MyProperties {
    @NotBlank(groups = AppNameRequired.class)
    private String appName;

    @NotBlank(groups = CredentialsRequired.class)
    private String username;

    @NotBlank(groups = CredentialsRequired.class)
    private String password;
}

Result

When I provide no property, nothing fails, which is desired. However, if I just use the following properties:

properties.username=
properties.password=

then both the service and the filter are created without any automatic validation issue, as this short modification shows:

@Bean
@ConditionalOnBean(MyService.class)
@Validated(AppNameRequired.class)
OncePerRequestFilter myFilter(@Valid MyProperties properties, MyService myService, Validator validator) {
    if(!validator.validate(properties, AppNameRequired.class).isEmpty()) {
        throw new IllegalArgumentException();  // Should not be reached if validation works, but is thrown on instantiation
    }

    return new MyFilter(properties, myService);
}

Trying with @Validated on properties class

I have also tried applying @Validated on MyProperties, but it did not change much. Furthermore, I noticed this in a more global case:

  • when there is @Validated on the class, and constraints without groups are all valid, no error is thrown, even if some constraints with groups are invalid
  • when there is @Validated on the class, but at least one constraint without group is violated, Spring fails the instantiation
  • when there is @Validated(AppNameRequired.class) on the class, and constraints without groups are all valid, no error is thrown, even if the constraints with group AppNameRequired are invalid

My conclusion, and my question

After all of this, my conclusion is that Spring does not support validation groups for bean validation. Hence, I wonder: is there a way to perform this conditional validation by relying on the Jakarta and Spring Boot annotations only, or am I forced to manually call a validator to perform this?

Share Improve this question asked Nov 22, 2024 at 11:54 Aisteru FirëAisteru Firë 2183 silver badges10 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

It seems that you are trying to use @Validated for spring beans, using Spring MVC approach.

First idea

From this article, looks like you need to declare an additional bean.

@Bean
    public static MethodValidationPostProcessor validationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

Second idea

Instead of relying on @ConditionalOnProperty during creation of MyService you can create a @Conditional bean which will validate values of the properties.

本文标签: javaSpring group validation does not work on autowired beansStack Overflow