Hi,
I have posted this earlier into the Search, Validator, Shards forum ... and realised only now that there is a separate forum for JSR 303 ... so please pardon me for duplicating the post into that forum and here, as there is no way to delete the post that I made in the other forum.
I need a way to interpolate a message, such that that the class implementing the ConstraintValidator can actually tell the custom MessageInterpolator what values to use for the message.
e.g.:
1) ValidationMessages.properties file has this entry:
Code:
transaction.hasAuthorityToAuthorise=User {userId} does not the authority to authorise this transaction as the calculated value is {transactionValue} and is above the limit of {maxLimit}.
2) The {userId} and {transactionValue} and {maxLimit} are not annotation parameters. The values to replace for these three message parameters are only available within the class that implements the ConstraintValidator interface. That is, the actual values to be used within that message are only available within the isValid() method. Furthermore, {transactionValue} is calculated by another layer of code that actually does the calculation, and performs a database operation to calculate that value. {maxLimit} is determined via a database query.
Looking through the forums, some have asked the same question, but the answers are not quite clear cut and sort of not clean. Here were some of the suggestions that I found:
1) Use the following within the isValid() method:Code:
ConstraintValidatorContex.getDefaultConstraintMessageTemplate();
ConstraintValidatorContex.disableDefaultConstraintViolation();
ConstraintValidatorContex.buildConstraintViolationWithTemplate().addConstraintViolation();
The problem with this approach is that:
Code:
if( !isValid ) {
String template = constraintContext.getDefaultConstraintMessageTemplate();
template = template.replaceAll("\\{userId\\}", userId);
constraintContext.disableDefaultConstraintViolation();
constraintContext.buildConstraintViolationWithTemplate(template).addConstraintViolation();
}
In the example above, constraintContext.getDefaultConstraintMessageTemplate() returns:
Code:
transaction.hasAuthorityToAuthorise
and not
Code:
User {userId} does not the authority to authorise this transaction as the calculated value is {transactionValue}
Thus, I then need to duplicate the work that ResourceBundleMessageIntepolator does to find the actual text that I need.
2) Use a custom MessageInterpolatorFair enough, and what I was thinking of, if only I can pass a Map of <String,Object>, and have the custom message interpolator then replace / subtitute any other text within the message that the default interpolator could not replace / substitute, with the values that I have in the Map.
Problem is, this Map then needs to be created inside the isValid() method, and somehow, the custom message interpolator needs access to this Map ... and I can't see a clear way of doing that using the MessageInterpolator.Context .. unless one sets these message values into the bean that was validated, so that it is available via MessageInterpolator.Context.getValidatedValue() ... but that means adding properties into the bean for the message interpolation, when the bean should not have any knowledge or logic about validation messages, as that is not the job of the bean, but the validation layer.
What am I missing ?
What have you / others have done ?