public class BindValidationMessagesHandler extends DefaultMessageHandler {
private static final String NAME = "messages";
private static final Map<CacheKey, Method> CACHE = new ConcurrentHashMap<>();
private final Method validationMethod;
public BindValidationMessagesHandler(Class<?> pmoClass, String property) {
this.validationMethod = CACHE.computeIfAbsent(new CacheKey(pmoClass, property), this::getValidationMethod);
}
private Method getValidationMethod(CacheKey key) {
String validationMethodName = "get" + StringUtils.capitalize(key.propertyName + StringUtils.capitalize(NAME));
try {
return key.pmoClass.getMethod(validationMethodName, MessageList.class);
} catch (NoSuchMethodException | SecurityException e) {
throw new LinkkiBindingException(String.format("Cannot find method %s(MessagesList) in %s",
validationMethodName, key.pmoClass.getName()),
e);
}
}
@Override
protected MessageList getRelevantMessages(MessageList messages, PropertyDispatcher propertyDispatcher) {
try {
if (propertyDispatcher.getBoundObject() instanceof Class<?>) {
// The bound object is most likely a column from a grid.
return new MessageList();
}
return (MessageList)validationMethod.invoke(propertyDispatcher.getBoundObject(), messages);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new LinkkiBindingException(String.format("Cannot invoke method %s(MessagesList) on %s",
validationMethod.getName(),
propertyDispatcher.getBoundObject()),
e);
}
}
}
Extending linkki
Custom message handling
It is possible to create your own annotation for message binding instead of using the provided @BindMessages
, for instance to disable a button if there are error messages.
The custom annotation has to be annotated with the meta-annotation @LinkkiMessages
.
Next, an implementation of LinkkiMessageHandler
is required.
In the case of @BindMessages
the implementation BindValidationMessagesHandler
extends DefaultMessageHandler
.
When a PMO property, for instance getDateOfBirth()
, is annotated with @BindMessages
, the PMO class and annotated elements are passed to the constructor of BindValidationMessagesHandler
and are used in BindValidationMessagesHandler.getRelevantMessages()
to retrieve and call the PMO’s method getDateOfBirthMessages()
:
Finally, the custom annotation requires an implementation of MessageHandlerCreator
, to create and return the implementation of LinkkiMessageHandler
.
E.g. with @BindMessages
, the creator class looks like:
class BindMessagesHandlerCreator implements MessageHandlerCreator<BindMessages> {
@Override
public LinkkiMessageHandler create(BindMessages annotation, AnnotatedElement annotatedElement) {
Method method = (Method)annotatedElement;
return new BindValidationMessagesHandler(method.getDeclaringClass(),
BoundPropertyAnnotationReader.getBoundProperty(method).getPmoProperty());
}
}