4.5.2.3.4. Validator

Validator is designed to check values entered into visual components.

Warning

Validation and input type checking should be differentiated. If a given component (e.g. TextField) data type is set to anything different than string (this can happen when binding to an entity attribute or setting datatype), then the component will not allow the user to enter a value that does not comply with this data type. When the component loses focus or when the user presses Enter, the component will show the previous correct value.

On the other hand, validation does not act immediately on data entry or focus loss, but rather when the component’s validate() method is invoked. It means that the component (and the entity attribute that it is linked to) may temporarily contain a value, which does not comply with the conditions of validation. It should not be a problem because the validated fields are typically located in edit screens, which automatically invoke validation for all their fields before commit. If the component is located not in an edit screen, its validate() method should be invoked explicitly in the screen controller.

In a screen XML-descriptor, a component validator can be defined in a nested validator elements. The validator element can have the following attributes:

  • script − path to a Groovy script performing validation.

  • class − name of a Java class implementing the Field.Validator interface.

Groovy validator scripts and standard classes of Java validators, located in the com.haulmont.cuba.gui.components.validators package support message attribute − a message displayed to a user when validation fails. The attribute value should contain either a message or a message key from the messages pack of the current screen. For example:

<validator class="com.haulmont.cuba.gui.components.validators.PatternValidator"
           message="msg://validationError"
           pattern="\d{3}"/>
# messages.properties
validationError = Input error

The validation mechanism is selected as follows:

  • If the value of the script attribute is not set and the validator element itself does not contain text with a Groovy expression, then the system will use a class defined in the class attribute as a validator.

  • If the validator element contains text, it will be used as a Groovy expression and executed using Scripting.

  • Otherwise, the system will use Scripting to run a Groovy script defined in the script attribute.

The value variable will be passed to a Groovy expression or script. It contains the value entered into a visual component. The expression or the script should return a boolean value: true − valid, false − not valid.

If a Java class is being used as a validator, it should have a default constructor without parameters or a constructor with the following set of parameters:

  • org.dom4j.Element, String – this constructor will receive the validator XML-element and the message pack name of the screen.

  • org.dom4j.Element – this constructor will receive the validator XML-element.

Tip

If the validator is implemented as an internal class, it should be declared with a static modifier and its name should be separated by "$", for example:

<validator class="com.sample.sales.gui.AddressEdit$ZipValidator"/>

The platform contains the set of implementations for the most frequently used validators (see com.haulmont.cuba.gui.components.validators package), which can be used in your project:

  • DateValidator

  • DoubleValidator

  • EmailValidator

  • IntegerValidator

  • LongValidator

  • PatternValidator

  • RangeValidator

  • ScriptValidator

  • StringValidator

A validator class can be assigned to a component not only using a screen XML-descriptor, but also programmatically – by submitting a validator instance into the component’s addValidator() method.

Example of creating a validator class for zip codes:

public class ZipValidator implements Field.Validator {
    @Override
    public void validate(Object value) throws ValidationException {
        if (value != null && ((String) value).length() != 6)
            throw new ValidationException("Zip must be of 6 characters length");
    }
}

Example of using a zip code validator and a standard pattern validator for fields of a FieldGroup component:

<fieldGroup>
    <field id="zip" required="true">
         <validator class="com.company.sample.gui.ZipValidator"/>
    </field>
    <field id="imei">
        <validator class="com.haulmont.cuba.gui.components.validators.PatternValidator"
               pattern="\d{15}"
               message="IMEI validation failed"/>
    </field>
</fieldGroup>

Example of setting a validator programmatically in a screen controller:

if (Boolean.TRUE.equals(parameter.getRequired())) {
    tokenList.addValidator(new Field.Validator() {
        @Override
        public void validate(Object value) throws ValidationException {
            if (value instanceof Collection && CollectionUtils.isEmpty((Collection) value)) {
                throw new ValidationException(getMessage("paramIsRequiredButEmpty"));
            }
        }
    });
}