In the previous parts we concentrated on constraint based server-side as well as client-side validation. In this fourth part of this series about MyFaces ExtVal, we'll look at some of the additional features that allow you to introduce custom mechanisms.
Tell me what's wrong
An important part of validation in a UI is the result displayed in case of a detected violation. ExtVal provides a pluggable mechanism that lets you provide a MessageResolver class per constraint via convention or dependency injection. It's also possible to use a default MessageResolver per validation module and many other possibilities. A MessageResolver takes a String as well as a Locale and transforms it to a localized message. Basically ExtVal provides an easy to use infrastructure for message resolving. Since there are a lot of different possibilities, and ExtVal will support you with using or integrating your preferred concept of message resolving, we won't take a close look at any particular approach here. There are several examples
that illustrate some of the available approaches.
It's important to understand that a MessageResolver is not a MessageInterpolator
. Compared to ExtVal, the Bean-Validation specification (JSR 303) specifies a MessageInterpolator
that is responsible for resolving the message text and replacing the placeholders with the values provided by the constraint. Both approaches allow you to load messages from any kind of data source. If you use the Bean Validation module of ExtVal you can benefit from both: the separation of resolving and the interpolation process performed by the bean-validation provider.
Besides message resolving, ExtVal also cares about topics like the correct labels. That means, if there is still a placeholder in the final error message, ExtVal will replace it with the label-text of the corresponding JSF component. In case of the Bean Validation module ExtVal automatically adds the label to the message, unless it is configured differently. That means ExtVal uses the same format as the default JSF validation messages and users won't see the difference. Furthermore, ExtVal ensures that there is a deterministic order of the violation messages, which allows easier automated testing of violations.
In addition to the Bean Validation Module, the community also created add-ons, such as the required label add-on for the Bean Validation
and Property Validation modules, which let you automatically adjust the rendered labels for required input components.
ExtVal allows you to register so called ValidationExceptionInterceptors
via an ExtVal startup-listener. Such a global ValidationExceptionInterceptors
will be called as soon as a constraint validator detects a violation, and it lets you implement advanced concepts. For example ExtVal uses this concept internally for handling the different violation severities. Therefore, users can use features like the violation severity warn
which shows the violation, but unlike the severity error
, the request-lifecycle will be continued. This also allows advanced add-ons, like the Continue with Warnings
add-on. It just blocks warnings the first time, showing the violation message, and if the user confirms the warning, the violation will be skipped at the next request. Figure 1 shows what a custom ValidationExceptionInterceptor looks like.
Figure 1 A custom ValidationExceptionInterceptor
Since ExtVal uses ValidationExceptionInterceptors internally, an optional concept for ordering the interceptors is needed in some cases. If the invocation order is important, it's possible to use the annotation @InvocationOrder to specify the order.
You can register such a custom interceptor via a naming convention, or via web.xml or an ExtVal startup-listener. The approach based on the ExtVal startup-listener supports two different possibilities. The first one is to pass an instance to the addValidationExceptionInterceptor method of the ExtValContext and the second one uses the new type-safe ExtVal configuration which can be registered via ExtValContextExtValCoreConfiguration.use (new CustomExtValCoreConfiguration(), true). In the custom implementation of the core configuration it's possible to specify the custom ValidationExceptionInterceptors by overriding the corresponding method. Instead of returning the custom ValidationExceptionInterceptor directly, this approach also allows you to integrate a custom configuration format easily.
Intercepting the validation process
Compared to the ValidationExceptionInterceptor mechanism, it's also possible to register ValidationExceptionInterceptors which are called in any case before and after validating a property. Another difference is that a PropertyValidationInterceptor can be registered for a single property or as a global implementation. Figure 2 shows what a custom PropertyValidationInterceptor looks like. In order to register a global PropertyValidationInterceptor it's possible to use the same concepts that were mentioned for the ValidationExceptionInterceptor mechanism.
Figure 2 shows a custom PropertyValidationInterceptor
As the name indicates, a global PropertyValidationInterceptor will be called for every property that gets validated whereas a local PropertyValidationInterceptor will be called before and after the validation of an ExtVal constraint that hosts the interceptor. That's possible due to the constraint aspect mechanism -- e.g. via @Required(parameters = CustomPropertyValidationInterceptor.class).
This fourth part illustrates some of the advanced features of MyFaces ExtVal, which also allow you to integrate custom mechanisms. Besides the several simple use cases we just discussed, such advanced features also can be used to integrate third-party validation engines or add-ons for special use cases like the Continue with Warnings add-on.