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+

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.

  • No labels