I've read some Q&As and guides (like Hibernate Documentation) as to how to work with Hibernate's ConstrainValidator, but none of them mention clearly how to interpolate a value in a specific position of a validation error message when creating your own custom validation annotation.
For example, if I have a validation error message that looks like this:
foo.bar.error=This value '{myValue}' is wrong.
I would like to obtain the following message if the validation fails:
The value 'some wrong value' is wrong.
The validation would be used like this:
public class SomeClass {
@CustomAnnotation(message="{foo.bar.error}")
public MyObject myObject;
...
}
public class MyObject {
private String myValue;
...
}
I've found a way to interpolate the message without much fuzz.
First set your ValidationMessages.properties
(or wherever your validation messages are stored) as before:
foo.bar.error=This value '{wrongValue}' is wrong.
Create your annotation like you normally would:
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Constraint(validatedBy = CustomValueValidator.class)
@Target(FIELD)
@Retention(RUNTIME)
public @interface CustomAnnotation {
String message() default "{foo.bar.error}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Implement your constraint validator like this:
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class CustomValueValidator
implements ConstraintValidator<CustomAnnotation, MyObject> {
@Override
public void initialize(final CustomAnnotation constraintAnnotation) {
// Extract any value you would need from the annotation
}
@Override
public boolean isValid(final MyObject myObject,
final ConstraintValidatorContext context) {
boolean valid;
// Add your validations over the 'myObject' object
if (!valid) {
((ConstraintValidatorContextImpl) context)
.addMessageParameter("wrongValue", myObject.getMyValue());
}
return valid;
}
}
Now all that is left is to use the annotation:
public class SomeClass {
// I'm using the default message. You could override it as a parameter
@CustomAnnotation
public MyObject anotherObject;
...
}