Open
Description
Hello!
You provide a class AbstractValidator
with this single constructor:
/**
* Constructs a validator with the given error message. The substring "{0}"
* is replaced by the value that failed validation.
*
* @param errorMessage
* the message to be included in a failed result, not null
*/
protected AbstractValidator(String errorMessage) {
Objects.requireNonNull(errorMessage, "error message cannot be null");
this.messageProvider = value -> errorMessage.replace("{0}",
String.valueOf(value));
}
And then almost all your validators extend this one.
That's perfectly fine... except if you have a webapp using i18n...
Image the following example: you are using a Binder for your form:
this.myBinder.forField(getMyTextField())
.withValidator(new DateRangeValidator("My Translated message using the current locale", null, LocalDate.now()))
.bind(Member::getBirthday, Member::setBirthday);
I created the object DateRangeValidator and because the errorMessage is a String, I have no other choice to directly provide the translated text using the current locale.
After, if the user changes his language, the only possibility for me to adapt the error message is to create again a new Binder ! :/
But if you add a constructor in AbstractValidator (and children) using your own functional interface ErrorMessageProvider, the issue is solved!
this.myBinder.forField(getMyTextField())
.withValidator(new DateRangeValidator(createErrorMessageProvider(key), null, LocalDate.now()))
.bind(Member::getBirthday, Member::setBirthday);
private ErrorMessageProvider createErrorMessageProvider(String key) {
return context -> callMyI18NProviderToGetTranslationOfKey(key);
}