You can embed the attribute value specified in the constraint annotation in the Bean Validation error message as follows. (Note that the content handled in this entry is premised on using Hibernate Validator)
Constraint annotation specification example
@Size(min = 4, max = 16)
private String foo;
Validation execution example
// ...
Bean bean = new Bean();
bean.foo = "123";
Set<ConstraintViolation<Bean>> violations = vb.validate(bean);
// ...
The error message generated in the above case would be "size must be between 4 and 16".
In the case I'm working on now, I was forced to get the reference value to be referred to when checking the input from the external setting (actually the property file). There was an option to check with logic without using Bean Validation, but I wanted to use the Bean Validation mechanism as much as possible for input checking, so I investigated how to implement it with Bean Validation.
Although it was not actually created, I decided to create an annotation that checks "the date is after the specified number of days" and a constraint annotation that gets the "specified number of days" part from the property file. ..
Example of creating constraint annotation
@DaysLater(days = "foo.daysLater", defaultValue = 5)
private LocalDate fooDate;
Property file setting example
foo.daysLater=10
src/main/resources/ValidationMessages.Properties setting example
com.example.validation.DaysLater.message = must be {days} days later
I'd like to say "must be 10 days later" as the error message when the constraint is violated ... Unfortunately, the default behavior is "must be foo.daysLater days later". Well, it's a natural result ...
I haven't investigated it properly, but when I looked at the specifications, there seemed to be no way to deal with it within the Bean Validation specifications. However, since the EL formula can be used when assembling the message, it may be possible to deal with it by mastering the EL formula.
When using Extensions provided by Hibernate Validation, the message You can change the values that can be referenced from the definition.
private int value; //Store property value from annotation attribute value (property key)
// ...
public boolean isValid(LocalDate targetValue, ConstraintValidatorContext context) {
boolean result = //Check contents omitted...
//If the check is NG, the default behavior is invalidated and arbitrary constraint violation information is generated.
if (!result) {
//Convert to the interface provided by Hibernate Validator to use the extension of Hibernate Validator
HibernateConstraintValidatorContext hibernateContext =
context.unwrap(HibernateConstraintValidatorContext.class);
//Disables the generation of default constraint violation information
hibernateContext.disableDefaultConstraintViolation();
//Generate arbitrary constraint violation information
hibernateContext
//In the message definition{value}To be able to refer to the value with
.addMessageParameter("days", this.days)
//Allow the value to be referenced by the variable name value in the EL expression in the message definition
.addExpressionVariable("days", this.days)
//Use the template specified in the annotation for the message template (same as the default behavior)
.buildConstraintViolationWithTemplate(hibernateContext.getDefaultConstraintMessageTemplate())
//Add constraint violation information
.addConstraintViolation();
}
return result;
}
With the above implementation, it is possible to embed the value corresponding to the property key instead of the property key in the message. By utilizing this mechanism, it is also possible to embed a "date when the check is OK" in the message.
public boolean isValid(LocalDate targetValue, ConstraintValidatorContext context) {
LocalDate validMinDate = LocalDate.now().plusDays(value);
boolean result = //Check contents omitted...
if (!result) {
HibernateConstraintValidatorContext hibernateContext =
context.unwrap(HibernateConstraintValidatorContext.class);
hibernateContext.disableDefaultConstraintViolation();
hibernateContext
.addMessageParameter("days", this.days)
.addExpressionVariable("days", this.days)
//Added the date when the check is OK
.addMessageParameter("validMinDate", validMinDate)
.addExpressionVariable("validMinDate", validMinDate)
.buildConstraintViolationWithTemplate(hibernateContext.getDefaultConstraintMessageTemplate())
.addConstraintViolation();
}
return result;
}
src/main/resources/ValidationMessages.properties
com.example.validation.DaysLater.message = must be {validMinDate} or later
The error message when the constraint is violated is "must be 2018-09-26 or later", which can be a more intuitive message.
If running on Hibernate Validator is a prerequisite, using the extensions introduced here will make it easier to compose messages with high usability. The project I'm currently working on can be executed on the Hivernate Validator, so I'm thinking of making effective use of this mechanism.