Skip to content

v0.7.2 Documentation

cduplichien edited this page Feb 18, 2013 · 26 revisions

Springjutsu Validation v0.7.2 Documentation & Reference Guide

What is Springjutsu Validation

Springjutsu Validation replaces standard JSR-303 validation annotations with robust XML validation definitions offering several possibilities not found in a standard bean validation library:

  • Simple creation and definition of custom rules
  • Options for form-specific contextual validation within Spring MVC and Spring Web Flow
  • Execution of conditional validation rules based on the outcome of another rule
  • Encapsulation of common patterns of multiple rules into reusable templates
  • Programmatic access via Expression Language to request parameters and other request data
  • Full i8n internationalization support by loading error messages and field labels from a spring message source
  • Easily apply validation rules and conditional validation to collection members

In Springjutsu Validation all validation is comprised of combinations of rules.

<!-- A rule looks like this. -->
<rule path="address.zipCode" type="exactLength" value="5"/>

As you might guess, the above rule constrains a field named "zipCode" found on a sub-bean field named "address" to be exactly 5 characters long.

When a rule fails error messages are created by looking up message codes from a spring MessageSource using conventions which can be specified within the configuration options. This error message is registered as a field error on the standard Spring Errors object.

Let's assume that the address bean was of type org.mycompany.coolproject.model.PostalAddress in our project. Let's also assume we have the following message properties defined:

# look up error messages - errors.<rule type>
errors.exactLength={0} must be exactly {1} characters long.
# look up field labels - <simple class name>.<field name>
postalAddress.zipCode=Postal Code

Springjutsu Validation fills in the message args, and the generated error message is:

Postal Code must be exactly 5 characters long.

This is usage at its most basic. But, before looking at more advanced usage we'll cover how to acquire Springjutsu Validation and configure it for use within your application.

Dependencies & Configuration

Maven Dependencies

(Please note that Springjutsu Validation requires a minimum Spring Framework version of 3.1.0.RELEASE)

The first step in adding Springjutsu Validation to a project is to acquire the appropriate artifacts from Maven Central. The dependency is as follows:

<dependency>
    <groupId>org.springjutsu</groupId>
    <artifactId>validation</artifactId>
    <version>0.7.2</version>
</dependency>

If you don't use maven for your dependencies, you can alternatively acquire the current validation jar directly from maven central: http://repo1.maven.org/maven2/org/springjutsu/validation/0.7.2/

Initial Configuration

Once the validation jar is safely nestled into your project, you can set it up as your default Validator with Spring by updating your Spring configuration thusly:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Note the validation namespace added to spring namespaces -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:validation="http://www.springjutsu.org/schema/validation"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
    http://www.springjutsu.org/schema/validation
    http://www.springjutsu.org/schema/validation-0.7.2.xsd">

    <!-- Create a springjutsu validation manager -->
    <validation:configuration validatorName="springjutsuValidator" />

    <!-- Enable Spring @MVC annotation driven controller model referencing our validator -->
    <mvc:annotation-driven validator="springjutsuValidator"/>

    <!-- Other beans... don't forget your message source! -->    

</beans>

As you can see, a bean named "springjutsuValidator" is created by the validation:configuration namespace element, and is set as the default spring validator by name reference. For additonal information on registering MVC validators, consult the spring documentation: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/htmlsingle/#validation-mvc-configuring

This is all the basic configuration that is required to begin using Springjutsu Validation. Configuration options accessible through the validation:configuration element will be shown in later sections.

About Validation Rules

Rules are defined in XML using the element. The only required attribute for a rule is the "type" attribute, which indicates the type of rule being evaluated. The attributes declarable for a rule are:

Attribute Name Usage
type Indicates the rule type being evaluated
path Indicates the path to the field being validated. When not specified, the root object under validation is passed to the rule instead of a specified field. Can also be an EL string.
value Indicates an argument to a rule. Can be a static string or an EL string. Can be left unspecified for rules not requiring an argument.
message Indicates an error message to display instead of the rule's default message. Use to customize the displayed message when the outcome of a rule has special meaning.
errorPath Overrides "path" attribute to indicate the field that should receive the error. Use to validate one field, but report the error on a different one.
collectionStrategy See Validating Collection Members.

Prepackaged Rules

Several rules come built into Springjutsu Validation and are configured by default. These are:

Rule Type Usage
alphabetic Will pass if the model is either all letters, empty, or null
alphanumeric Will pass if the model is all letters and numbers, empty, or null
email Will pass if the model is a valid email address, empty, or null
maxLength Will pass if the String value of the model is less than or equal to the number of characters specified by the argument, empty, or null
minLength Will pass if the String value of the model is greater than or equal to the number of characters specified by the argument, empty, or null
numeric Will pass if the model is all numbers, empty, or null
required Will pass if the model is neither null or empty
notEmpty Same as required but has better semantics for use in conditional validation
matches Will pass if the String value of the model is the same as the String value of the argument

If you would prefer that the default rules not be registered, they can be disabled through the configuration element:

<validation:configuration validatorName="springjutsuValidator">
    <validation:rules-config addDefaultRuleExecutors="false"/>
</validation:configuration>

Defining Custom Rules

A rule is evaluated using a class called a RuleExecutor. Springjutsu validation provides a few extension options for creating custom RuleExecutor classes:

Class Name Purpose
org.springjutsu.validation.executors.RuleExecutor This is the most basic interface. It provides a simple boolean validate method which accepts a model to be validated, and an optional argument, and should return true if the rule passed.
org.springjutsu.validation.executors.ValidWhenEmptyRuleExecutor This is a convenient extension point for creating validation rules that will pass when the model is null or empty. Use it to create rules that shouldn't fail when the model isn't present. The doValidate method has the same semantics as the RuleExecutor's validate method.
org.springjutsu.validation.executors.RegexMatchRuleExecutor This is a convenient extension point for creating rules which should simply require that the String value of model being validated should match a regular expression returned by the abstract getRegularExpression method. It is the basis of the alphabetic, numeric, and alphanumeric rules.

An important note is that all Springjutsu Validation Rule Executors are registered as spring beans. This means they can have autowired dependencies injected from the Spring Container.

Let's say we're writing an issue tracker and have a field that allows the user to specify the username of an assignee. We need to ensure that the assignee for that username exists and is active. Let's create a rule executor to fulfill this requirement.

public class ValidUsernameRuleExecutor extends ValidWhenEmptyRuleExecutor {
	
    @Autowired
    private UserService userService; // pretending this is part of our project.
	
    @Override
    public boolean doValidate(Object model, Object argument) {
        User user = userService.findByUsername((String) model);
        return user != null && user.isActive();
    }
}

There we go. One rule executor using autowired dependencies to validate that our username corresponds to an existing and active user. Next we need to register the RuleExecutor with Springjutsu validation. We have two options.

Option 1: Use the ConfiguredRuleExecutor annotation at the class level.

// Make our rule available using the rule type "validUsername"
@ConfiguredRuleExecutor(name="validUsername")
public class ValidUsernameRuleExecutor extends ValidWhenEmptyRuleExecutor {
  // implementation
}

Option 2: Configure the RuleExecutor manually in XML.

<validation:configuration validatorName="springjutsuValidator">
    <validation:rules-config addDefaultRuleExecutors="false">
        <!-- Make our rule available using the rule type "validUsername" -->
        <validation:rule-executor name="validUsername" class="com.mycompany.project.validation.ValidUsernameRuleExecutor" />
    </validation:rules-config>
</validation:configuration>

Writing a Rules XML

An XML validation file is actually a spring bean definition file. Validation rules are declared on a per-class basis: our recommendation is to have one file per class. Since this means adding multiple bean definition files to your spring context, you may want to review Spring's documentation on constructing contexts from multiple files. The use of ANT paths is especially simple. http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/htmlsingle/#resources-app-ctx

Each class has its rules defined in an entity element.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springjutsu.org/schema/validation"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="
    http://www.springjutsu.org/schema/validation 
    http://www.springjutsu.org/schema/validation-0.7.2.xsd
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <!-- Going to define rules for our Person class -->
    <entity class="com.mycompany.project.model.Person">
        <!-- and rules can go here -->
        <rule path="firstName" type="alphabetic" />
        <rule path="firstName" type="maxLength" value="50" />
        <!-- etc... -->
    </entity>

</beans:beans>

For focus and brevity, the following examples will assume the above namespaces and wrapping beans:beans element are present, and include instead only the entity elements.

Basic Validation

Let's say that we want to validate that the fields on a company's name and it's address are present. The classes look like this:

public class Company {
    private String name;
    private Address address;
    // ... getters and setters ...
}

public class Address {
    private String street;
    private String city;
    private String zipCode;
}

Then, we have a couple options. We could put all the validation on the Company object.

<entity class="com.mycompany.project.model.Company">
    <rule path="name" type="required" />
    <rule path="address.street" type="required" />
    <rule path="address.city" type="required" />
    <rule path="address.zipCode" type="required" />
</entity>

But, that may not be ideal, because we can't reuse those address rules on any other object that has an address. But if we look at the next section, we can take advantage of recursive sub bean validation and move those address rules out to an address entity.

Recursive Sub-Bean Validation

Let's say we have rules declared for a Company class, and an Address class, and the Company class has a field of type Address.

<entity class="com.mycompany.project.model.Company">
    <rule path="name" type="required" />
</entity>

<entity class="com.mycompany.project.model.Address">
    <rule path="address.street" type="required" />
    <rule path="address.city" type="required" />
    <rule path="address.zipCode" type="required" />
</entity>

Now when we validate a Company object, the Address class rules will be applied to the Address-type field on the Company object as well. Springjutsu Validation will automatically validate sub bean fields of a parent object recursively when both the owning object's class and the field type have entity definitions.

There are several ways to delcaratively include or exclude fields from this behavior. For this example we'll have a Company object with an Address field that we want to validate when the company is validated, and a parentCompany field of type Company that we'll want to exclude from validation:

public class Company {
    private String name;
    private Address address; // we want to validate this
    private Company parentCompany; // we don't want to validate this
    // ... getters and setters ...
}

Option 1: Exclude parentCompany via XML: since address isn't excluded it will still be validated recursively.

<entity class="com.mycompany.project.model.Company">
    <recursion-exclude propertyName="parentCompany" />
    <!-- Rules go here as they normally do -->
</entity>

Option 2: Exclude parentCompany via bean annotation: since address isn't excluded it will still be validated recursively.

public class Company {
    private String name;
    private Address address;
    
    @RecursiveValidationExclude // in package org.springjutsu.validation.rules
    private Company parentCompany;

    // ... getters and setters ...
}

Option 3: Include address via XML: since parentCompany isn't included it won't be validated recursively.

<entity class="com.mycompany.project.model.Company">
    <recursion-include propertyName="address" />
    <!-- Rules go here as they normally do -->
</entity>

Option 4: Include address via bean annotation: since parentCompany isn't included it won't be validated recursively.

public class Company {
    private String name;

    @RecursiveValidationInclude // in package org.springjutsu.validation.rules
    private Address address;

    private Company parentCompany;

    // ... getters and setters ...
}

Option 5: Include / Exclude using your own annotations - Custom Include and Exclude annotations can be defined in the configuration element. This can be useful if you wanted to exclude all @Transient fields, for instance. These are usable in addition to the default annotations and XML include and exclude options.

<validation:configuration validatorName="springjutsuValidator">
    <validation:rules-config>
        <validation:recursion-exclude-annotation class="javax.persistence.Transient"/>
        <validation:recursion-include-annotation class="javax.persistence.Embedded"/>
    </validation:rules-config>
</validation:configuration>
public class Company {

    private String name;

    @Embedded
    private Address address;

    @Transient
    private Company parentCompany;

    // ... getters and setters ...
}

Validating Forms & Web Flow States

Conditional Validation

Validating Collection Members

Validation Templates

Sub Classes & Validation Inheritance

Using Expression Language

Message Lookup Options

Handling Validation Success & Failure

Clone this wiki locally