Dormouse
Dormouse

Reputation: 1637

Spring Bean Validation with configurable constraint values

I'd like to make Java Bean Validation constraints configurable by Spring, possibly by using properties. An example:

class Pizza {

    @MaxGramsOfCheese(max = "${application.pizza.cheese.max-grams}")
    int gramsOfCheese;

}

I haven't been able to get this to work or find much documentation about this.

Is something like this even possible? I know that messages are configurable in a Validationmessages.properties file, so I'm hoping something similar is possible for constraint values.

Upvotes: 4

Views: 4069

Answers (2)

Yavuz Tas
Yavuz Tas

Reputation: 354

In addition to @Madhu Bhat you can configure your ConstraintValidator class to read properties from Spring's Environment.

public class MaxGramsOfCheeseValidator implements ConstraintValidator<MaxGramsOfCheese, Integer> {

    @Autowired
    private Environment env;

    private int max;

    public void initialize(MaxGramsOfCheese constraintAnnotation) {
        this.max = Integer.valueOf(env.resolvePlaceholders(constraintAnnotation.max()));
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return value != null && value <= this.max;
    }

}

Thus you can use @MaxGramsOfCheese annotation on different fields with different parameters which may be more appropriate in your case.

class Pizza {

    @MaxGramsOfCheese(max = "${application.pizza.cheddar.max-grams}")
    int gramsOfCheddar;

    @MaxGramsOfCheese(max = "${application.pizza.mozerella.max-grams}")
    int gramsOfMozerella;

}

Upvotes: 4

Madhu Bhat
Madhu Bhat

Reputation: 15253

For any custom validation, you need to implement a custom validator by implementing the ConstraintValidator interface, and then provide that custom validator to the custom validation annotation that you create.

The custom validator:

public class MaxGramsOfCheeseValidator implements ConstraintValidator<MaxGramsOfCheese, Integer> {

    @Value("${application.pizza.cheese.max-grams}")
    protected int maxValue;

    @Override
    public void initialize(MaxGramsOfCheese constraintAnnotation) {
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return value != null && value <= maxValue;
    }

}

The custom validation annotation:

@Documented
@Constraint(validatedBy = {MaxGramsOfCheeseValidator.class})
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MaxGramsOfCheese {
    String message() default "Some issue here"; //message to be returned on validation failure

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

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

Using the custom validation annotation:

class Pizza {

    @MaxGramsOfCheese
    int gramsOfCheese;

}

Note that if you want the value for the annotation to be accessed from the properties file, you'll have to provide that in the custom validator as shown.

Upvotes: 3

Related Questions