Проверяйте поля, только если другое поле имеет значение false - PullRequest
0 голосов
/ 17 октября 2019

Предположим, у меня есть класс @ConfigurationProperties, который должен проверять набор полей на основе значения другого поля. Например, SdkProperties имеет поле enabled. Только когда enabled равно true, остальные поля должны быть проверены.

SdkProperties

@Configuration
@ConfigurationProperties(...)
@Data
@Validated
public class SdkProperties
{
    private boolean enabled;

    @NotEmpty
    private String apiKey

    // ... etc.
}

Аннотация @NotEmpty должна проверяться только в том случае, если enabled is true.

Как правильно это сделать?

Я видел примеры использования @AssertTrue и isValid для обработки проверки вручную. Но я не хочу этого делать.

Интересно, можно ли это сделать с помощью групп проверки?

1 Ответ

0 голосов
/ 17 октября 2019

Вы можете написать пользовательский ConstraintValidator.


@Configuration
@ConfigurationProperties(prefix = "sdk")
@Validated
@NotEmptyWhenEnabled // <----- custom validation -----
@Data
class SdkProperties {

    private boolean enabled;
    private String apiKey;
}

@Constraint(validatedBy = {NotEmptyWhenEnabledValidator.class})
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface NotEmptyWhenEnabled {
    String message() default "SDK apiKey needed when SDK is enabled";

    Class[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

class NotEmptyWhenEnabledValidator implements ConstraintValidator<NotEmptyWhenEnabled,SdkProperties> {

    @Override
    public boolean isValid(SdkProperties sdkProperties, 
                           ConstraintValidatorContext constraintValidatorContext) {
        boolean enabled = sdkProperties.isEnabled();
        boolean empty = null == sdkProperties.getApiKey() || sdkProperties.getApiKey().isEmpty();
        return !enabled || (enabled && !empty);
    }
}

Затем вы получите приятное сообщение при запуске, когда SDK включен , но API-ключ не *Предоставляется 1008 *.

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'sdk' to so.demo.SdkProperties$$EnhancerBySpringCGLIB$$1ecd6003 failed:

    Reason: SDK apiKey needed when SDK is enabled


Action:

Update your application's configuration


Process finished with exit code 0

РЕДАКТ.

Начиная с spring-boot-2.2.0.RELEASE (16 октября 2019 г.), у вас есть другой вариант. Вы можете проверить свойства в конструкторе.

, используя: Immutable @ ConfigurationProperties binding

Свойства конфигурации теперь поддерживают привязку на основе конструктора, что позволяет @ConfigurationProperties -аннотированный класс, чтобы быть неизменным. Связывание на основе конструктора можно включить, пометив класс @ConfigurationProperties или один из его конструкторов @ConstructorBinding. Аннотации, такие как @DefaultValue и @DateTimeFormat, могут использоваться для параметров конструктора, которые предоставляются привязкой свойства конфигурации.

ref: boot-features-external-config-constructor-binding

так в вашем случае ...

@ConfigurationProperties(prefix = "sdk")
class SdkProperties {

    private boolean enabled;
    private String apiKey;

    @ConstructorBinding
    public SdkProperties(boolean enabled, String apiKey) {
        this.enabled = enabled;
        this.apiKey = apiKey;
        // direct validation in the constructor
        boolean apiKeyNullOrEmpty = null == apiKey || apiKey.isEmpty();
        Assert.isTrue(!enabled || !apiKeyNullOrEmpty, "When SDK is enabled, a SDK-api key is mandatory!");
    }

    public boolean isEnabled() {  return enabled; }
    public void setEnabled(boolean enabled) { this.enabled = enabled; }
    public String getApiKey() {return apiKey; }
    public void setApiKey(String apiKey) { this.apiKey = apiKey; }
}
...