It looks like recursion will always take place for a user-defined package, so in fact I can not translate standard messages for example, for size.
The Hibernate Validator ResourceBundleMessageInterpolator creates two instances of the ResourceBundleLocator (for example, PlatformResourceBundleLocator), one for UserDefined validation messages, userResourceBundleLocator, and the other for JSR-303 Standard validation messages, defaultResourceBundleLocator.
Any text that appears in two braces, for example. {someText} in the message is considered as replacementToken. ResourceBundleMessageInterpolator is trying to find an appropriate value that can replace replaceToken in ResourceBundleLocators.
- first in UserDefinedValidationMessages (which is recursive)
- then in DefaultValidationMessages (which is not recursive).
So, if you put the standard JSR-303 message in a custom ResourceBundle, say validation_erros.properties , it will be replaced with your custom message. See IN THIS EXAMPLE The standard NotNull check message "cannot be null" is replaced with the custom message "MyNotNullMessage".
How can I connect my own message to the source and have the parameters replaced in the message?
my.message = property {prop} is invalid
After going through both ResourceBundleLocators, the ResourceBundleMessageInterpolator finds an additional replacement for replaceTokens with an allowed message (enabled by both packages). These replaceToken are nothing more than Annotation attribute names ; if such replaceTokens are in a permitted Message, they are replaced with Annotation attribute values .
ResourceBundleMessageInterpolator.java [Line 168, 4.1.0.Final]
resolvedMessage = replaceAnnotationAttributes( resolvedMessage, annotationParameters );
By providing an example to replace {prop} with a custom value, I hope this helps you ....
MyNotNull.java
@Constraint(validatedBy = {MyNotNullValidator.class}) public @interface MyNotNull { String propertyName(); //Annotation Attribute Name String message() default "{myNotNull}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default {}; }
MyNotNullValidator.java
public class MyNotNullValidator implements ConstraintValidator<MyNotNull, Object> { public void initialize(MyNotNull parameters) { } public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) { return object != null; } }
User.java
class User { private String userName;
validation_errors.properties
notNull={propertyName} cannot be null
Test
public void test() { LocalValidatorFactoryBean factory = applicationContext.getBean("validator", LocalValidatorFactoryBean.class); Validator validator = factory.getValidator(); User user = new User("James", "Bond"); user.setUserName(null); Set<ConstraintViolation<User>> violations = validator.validate(user); for(ConstraintViolation<User> violation : violations) { System.out.println("Custom Message:- " + violation.getMessage()); } }
Exit
Custom Message:- userName cannot be null