3

I have a variable called notification.max-time-to-live in application.yaml file and want to use this as the value of javax.validation.constraints.@Max() annotation.

I've tried in many ways (using env.getProperty(), @Value, etc) and it says it must be a constant value, is there any way to do this?

  • 1
    No. Those annotations are processed by javax.validation not Spring. So no this isn't possible. You could write your own validator which reads this value and validates accordingly. – M. Deinum Sep 27 '21 at 17:37
  • To voters: The answer to the question is no, but the question _as a question_ is reasonable to ask. – chrylis -cautiouslyoptimistic- Sep 27 '21 at 17:40
  • Does this answer your question? [Javax Validation - Values from Properties](https://stackoverflow.com/questions/61768104/javax-validation-values-from-properties) – damndemon Aug 11 '22 at 11:58

1 Answers1

2

I know this does not directly answer my question and as M. Deinum already said the answer is no. Nonetheless it's a simple workaround.

It's true that @Max and other javax annotations do not let us use dynamic values, however, we can create a custom annotation (as M. Deinum suggested) that uses values from application.yaml with spring @Value.

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = ValidTimeToLiveValidator.class)
public @interface ValidTimeToLive {

    String message() default "must be less than or equal to %s";

    Class<?>[] groups() default { };

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

And the respective validator.

public class ValidTimeToLiveValidator implements ConstraintValidator<ValidTimeToLive, Integer> {

    @Value("${notification.max-time-to-live}")
    private int maxTimeToLive;

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        // leave null-checking to @NotNull
        if (value == null) {
            return true;
        }
        formatMessage(context);
        return value <= maxTimeToLive;
    }

    private void formatMessage(ConstraintValidatorContext context) {
        String msg = context.getDefaultConstraintMessageTemplate();
        String formattedMsg = String.format(msg, this.maxTimeToLive);
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(formattedMsg)
               .addConstraintViolation();
    }
}

Now we just need to add this custom annotation in the respective class.

public class Notification {

    private String id;
 
    @ValidTimeToLive
    private Integer timeToLive;

    // ...
}