Improve the Bean-Validation Integration
Basic Information
Basic information about the setup is available here.
ExtVal Annotations for BV
ExtVal r3+
- @BeanValidation
- @ModelValidation
Mapping to custom implementations is not supported. However, since there is a generic implementation behind the scenes (ExtValBeanValidationContext) it's easy to implement an add-on which provides independent annotations or tags. The add-on just has to use the information provided by such custom implementations and add the information to the context. So you can use your own annotations and outside of the add-on you don't introduce a direct dependency to ExtVal.
ExtVal r4+
- Annotations of ExtVal r3
- @ConstraintSource
- @IgnoreConstraintSource
- @TargetProperty
- @TargetPropertyId
Mapping to custom implementations is supported (to get rid of import statements of ExtVal classes).
Payload for BV
ExtVal r3+
- ViolationSeverity.Info
- ViolationSeverity.Warn
- ViolationSeverity.Error (blocking violation)
- ViolationSeverity.Fatal (blocking violation)
- DisableClientSideValidation
Mapping to custom implementations is supported (to get rid of import statements of ExtVal classes).
JSF Messages
It's not nice to have messages in different places. Instead of tweaking BV itself, ExtVal provides a mechanism to resolve the message from a different location. By default BV just knows the bundle: ValidationMessages in the root package.
However, since we are in a JSF application you might already have a message bundle for your messages.
E.g.:
<application> <resource-bundle> <base-name>org.apache.myfaces.demo.app_messages</base-name> <var>app_messages</var> </resource-bundle> </application>
To join these messages for your BV violation messages you just have to use the following code in a custom extval-startup listener:
StaticInMemoryConfiguration config = new StaticInMemoryConfiguration(); config.addMapping(BeanValidationVirtualValidationStrategy.class.getName(), JsfAwareMessageResolver.class.getName()); ExtValContext.getContext().addStaticConfiguration(StaticConfigurationNames.VALIDATION_STRATEGY_TO_MESSAGE_RESOLVER_CONFIG, config);
The implementation of the message resolver is quite easy:
import org.apache.myfaces.extensions.validator.core.validation.message.resolver.DefaultValidationErrorMessageResolver; public class JsfAwareMessageResolver extends DefaultValidationErrorMessageResolver{ public ApplicationMessageBundleAwareMessageResolver() { setMessageBundleVarName("messages"); } }
... as alternative for using the fully qualified resource-bundle you can also use the method setMessageBundleBaseName.
As alternative for an easier configuration, you can use one of the config add-ons e.g. provided by os890.
Hint:
You don't have to add a placeholder for the label. It's done automatically. To change the default label/message template use the mechanism specified by JSF 2 (also in JSF 1.x applications) (see: javax.faces.validator.BeanValidator.MESSAGE and javax.faces.validator.BeanValidator.MESSAGE_detail)
BV Classes Only
If the sw-architecture of your application restricts the usage of ExtVal outside the View-Layer it's possible to map the default implementations to custom implementations. That means: The mapping takes place at startup (in the View-Layer) and in all classes outside the startup-listener you can use your custom implementations. Since ExtVal doesn't use classpath scanning you have to use the following implementations in a custom startup listener.
STOP reading here if you just need an intro - normally you don't have to care about the part below...
Mapping Payload
Custom Severity Payload Implementations
StaticInMemoryConfiguration config = new StaticInMemoryConfiguration(); config.addMapping(ViolationSeverity.Info.class.getName(), org.mypackage.CustomViolationSeverity.Info.class.getName()); config.addMapping(ViolationSeverity.Warn.class.getName(), org.mypackage.CustomViolationSeverity.Warn.class.getName()); config.addMapping(ViolationSeverity.Fatal.class.getName(), org.mypackage.CustomViolationSeverity.Fatal.class.getName()); ExtValContext.getContext().addStaticConfiguration(VALIDATION_PARAMETER_CONFIG, config);
Custom DisableClientSideValidation Payload Implementation
StaticInMemoryConfiguration config = new StaticInMemoryConfiguration(); config.addMapping(DisableClientSideValidation.class.getName(), org.mypackage.CustomDisableClientSideValidation.class.getName()); ExtValContext.getContext().addStaticConfiguration(VALIDATION_PARAMETER_CONFIG, config);
Full Backward Compatibility
If you aren't using a special add-on which adds dynamic constraints, you can re-activate the support of the required attribute in combination with component initialization for mandatory fields. So it's possible to use the required attribute as well as constraints for mandatory fields + the support for required component initialization.
ExtValContext extValContext = ExtValContext.getContext(); extValContext.addGlobalProperty("mode:init:required", true); extValContext.addGlobalProperty("mode:reset:required", false);
Performance Tuning
If you would like to use ExtVal only for BV, you can tune ExtVal via the following steps:
If you don't like to implement plain ExtVal constraints, you can deregister the default validator via:
ExtValContext.getContext().denyRendererInterceptor(ValidationInterceptor.class);
If you don't like to use JSR 303 based model validation, you can remove the phase listener.
JsfUtils.deregisterPhaseListener(new ModelValidationPhaseListener());
If you don't use further ExtVal add-ons which do some magic stuff, you can reset the renderer proxy via:
ExtValContext.getContext().addGlobalProperty(ExtValRendererProxy.KEY, null);
Since ExtVal v4+
If you don't need the mapped constraint source feature, you can deregister the validator via:
ExtValContext.getContext().denyRendererInterceptor(MappedConstraintSourceBeanValidationModuleValidationInterceptor.class);
Deactivate Special Behaviours
Deactivate @NotNull validation
If you don't like to use @NotNull for mandatory input fields, you can use:
<context-param> <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> <param-value>false</param-value> </context-param>
Deactivate Parts of ExtVal
There are a lot of possibilities for fine grained customization and deactivation.
This section just covers how to deactivate the building blocks just for testing in development mode.
Deactivate All Parts
Due to the required mojarra support there is just a vm-parameter to completely deactivate all ExtVal modules.
-Dorg.apache.myfaces.extensions.validator.DEACTIVATE_ALL=true
Deactivate the Core
The core automatically registers 2 classes ExtValStartupListener and ExtValRenderKitFactory.
For deactivating only the ExtVal artifacts registered by the core you can use:
<context-param> <param-name>org.apache.myfaces.extensions.validator.core.startup.ExtValStartupListener:DEACTIVATED</param-name> <param-value>true</param-value> </context-param>
For a complete core deactivation you also have to use:
<context-param> <param-name>org.apache.myfaces.extensions.validator.DEACTIVATE_RENDER_KIT_FACTORY</param-name> <param-value>true</param-value> </context-param>
If you are using mojarra you have to use the vm-parameter:
-Dorg.apache.myfaces.extensions.validator.DEACTIVATE_RENDER_KIT_FACTORY=true
Deactivate the Bean-Validation Integration
If you added the BV validation module of ExtVal to your classpath and you would like to deactivate it for some test purposes you don't have to remove it - just use:
<context-param> <param-name>org.apache.myfaces.extensions.validator.beanval.startup.BeanValidationStartupListener:DEACTIVATED</param-name> <param-value>true</param-value> </context-param>
Deactivate your ExtVal-Startup-Listener
As you see the syntax is always the same. Just use the fully qualified class name of your startup-listener + :DEACTIVATED as postfix.