Dashboard > Spring Modules > Using Valang validator
  Spring Modules Log In View a printable version of the current page.  
  Using Valang validator
Added by Steven Devijver, last edited by Uri Boness on Jun 06, 2006  (view change)
Labels: 
(None)

Work in progress

This article is a work in progress. It's currently being reviewed.
If you have any remarks about this text please send them to dev@springmodules.dev.java.net.

Note

In release 0.4, valang was moved out of the sandbox. This move was part of a general restructuring of the validation module (now valang as well as commons validator support) are part of the validation module) in which package names were changed, bugs were fixed, and new features were added. For more information about these changes, please refer to the change log of this release.

Valang validator allows you to write declarative validation rules using an intuitive syntax. The purpose of Valang validator is:

  • to quickly write validation rules without the need to create a class or write Java code.
  • to ease the use of the Spring validation tools.
  • to make validation rules compact, easily readable and maintainable.

Getting started

Getting the code

To use Valang validator you need to get the latest Spring Modules from CVS and run ant sandbox.jar.

To add your own validator using Valang validator in your Spring configuration file use the org.springmodules.validation.ValangValidatorFactoryBean class:

<bean id="myValidator" class="org.springmodules.validation.valang.ValangValidator">
   <property name="valang">
      <value><![CDATA[
{ firstName : length(?) < 30 : 'First name too long' }
{ lastName : length(?) < 50 : 'Last name too long' }
      ]]></value>
   </property>
</bean>

 

Usage

ValangValidator is a org.springframework.validation.Validator implementation. Any bean can be validated by this validator. However, if the bean does not contain a property used in the validation script an exception will be thrown.

Note

Prior to release 0.4, the org.springmodules.validation.ValangValidatorFactoryBean could be used as an alternative to org.springmodules.validation.ValangValidator. Since both classes served the same purpose, the former was deprecated and is planned to be removed in 0.5.

 

Syntax

The Valang syntax consists of one syntax that can be repeated:

( "{" <key> : <rule> : <message> : [ <error_code> [ : <error_parameters> ] ] "}" )+

 

If evalutation of the rule fails the key is rejected with the message and optionally the error code and error parameters.

<key>

<key> is mandatory. Its value is used as a reject code when the evaluation of the rule fails. The value of the key may or may not be a bean property.

<rule>

<rule> is mandatory. The rule syntax is a set of one or more expressions combined with parentheses:

<expression> ::= ( <predicate> | "(" <predicates> ")" )
<predicates> ::= <expression> ( ( "AND" | "OR" ) <expression> )*
<rule> ::=  <predicates>

 

<predicate>

A predicate is a simple evaluation against and operator involving literals, bean properties or both and optionally functions and mathematical experessions.

Operators

Supported operators are:

  • Binary operators:
    • String, boolean, date and number operators:
      • = | == | IS | EQUALS
      • != | <> | >< | IS NOT | NOT EQUALS
    • Number and date operators:
      • > | GREATER THAN | IS GREATER THAN
      • < | LESS THAN | IS LESS THAN
      • => | >= | GREATER THAN OR EQUALS | IS GREATER THAN OR EQUALS
      • <= | =< | LESS THAN OR EQUALS | IS LESS THAN OR EQUALS
  • Unary operators:
    • Object operators:
      • IS NULL | NULL
      • IS NOT NULL | NOT NULL
    • String operators:
      • HAS TEXT
      • HAS NO TEXT
      • HAS LENGTH
      • HAS NO LENGTH
      • IS BLANK
      • IS NOT BLANK
      • IS UPPERCASE | IS UPPER CASE | IS UPPER
      • IS NOT UPPERCASE | IS NOT UPPER CASE | IS NOT UPPER
      • IS LOWERCASE | IS LOWER CASE | IS LOWER
      • IS NOT LOWERCASE | IS NOT LOWER CASE | IS NOT LOWER
      • IS WORD
      • IS NOT WORD
  • Special operators:
    • BETWEEN
    • NOT BETWEEN
    • IN
    • NOT IN
    • NOT

These operators are case insensitive. Binary operators have a left and a right side. Unary operators only have a left side.

Value types for both sides of binary operators must always match.

Some invalid examples:

name > 0
age == 'some string'

 

BETWEEN / NOT BETWEEN operators

The between and not between operators have a special syntax:

<between_operator> ::= <left_side> BETWEEN <value> AND <value>
<not_between_operator> ::= <left_side> NOT BETWEEN <value> AND <value>

 

Both the left side and the values can be any valid combination of literals, bean properties, functions and mathematical operations.

Some examples:

width between 10 and 90
length(name) between minLength and maxLength

 

IN / NOT IN operators

The in and not in operators have a special syntax:

<in_operator> ::= <left_side> IN <value> ( "," <value> )*
<not_in_operator> ::= <left_side> NOT IN <value> ( "," <value> )*

Both the left side and the values can be any valid combination of literals, bean properties, functions and mathematical operations.

There's another special syntax where a java.util.Collection, java.util.Enumeration, java.util.Iterator or object array instance can be retrieved from a bean property. The values of said instance are than used as right side of the in or not in operator. This feature allows you to create dynamic sets of values based on other values of the bean.

<special_in_operator> ::= <left_side> IN "@"<bean_property>
<special_not_in_operator> ::= <left_side> NOT IN "@"<bean_property>

 

Some examples:

size in 'S', 'M', 'L', 'XL'
size in @sizes

 

NOT operator

The not operator has a special syntax:

<not_operator> ::= "NOT" <expression>

The not operator inverses the result of one or a set of predicates.

Literals

Supported literals are:

  • string
  • number
  • date
  • boolean
Spring literals

Strings are quoted with single quotes:

'Bill'
'George'
'Junior'

 

 

Number literals

Number literals are unquoted and are parsed by java.math.BigDecimal.

0.70
1
2000
-3.14

 

Date literals

Date literals are delimited with square brackets and are parsed upon each evalution by a special purpose date parser.

TODO: write documentation for date parser.

[T<d]
[2005-05-28]

 

Boolean literals

Boolean literals are not quoted.

<boolean> ::= ( "TRUE" | "YES" | "FALSE" | "NO" )

 

Bean properties

Type the name of the property to refer to a bean property:

firstName
lastName
address.zipCode
address.country.code

 

The special bean property ? (question mark) refers to the key. If you want to use ? make sure the key corresponds to a valid bean property.

Lists elements

List elements can be accessed through their index number in the list.

users[0].name = 'Steven'

 

Map entries

Values in map entries can be accessed through their key names. Keys must be string values.

companies[Interface21].customers[0].name

 

Functions

Function syntax is:

function ::= <function_name> "(" ( <literal> | <bean_property> | <function> ) ( "," ( <literal> | <bean_property> | <function> ) )* ")"

 

Functions shipped with Valang validator are:

Name Description
length Returns the size of the passed in collection or array. If the passed in argument is neither,
the length of the string returned from the toString() call on the passed in argument.
len see length
size see length
count see length
match
Matches the given regular expression (first argument) to the string returned from the toString() call on the passed in value (second argument).
matches
see match
email
Returns true if the string returned from the toString() call on the passed in argument
represents a valid email
upper Convert the value of the toString() method of a value to upper case.
lower same as upper but lower case.
! not operation on a boolean value.
resolve wrap string in org.springframework.context.support.DefaultMessageSourceResolvable.
inRole Accepts a role name as an argument and returns true if the current user has this role. This function uses Acegi to fetch the current user.

Function examples:

length(?)
size(upper('test'))
upper(firstName)

 

Mathematical expressions

Supported mathematical operators are:

  • +
  • -
  • *
  • / | div
  • % | mod

Parentheses are supported and expression are parsed left to right so that

2 - 3 + 5 = 4

 

Values in expression can be literals, bean properties and functions.

Expression examples:

(2 * (15 - 3) + ( 20 / 5 ) ) * -1
(22 / 7) - (22 div 7)
10 % 3
length(?) mod 4

 

<message>

<message> is mandatory but can be an empty string if not used. The message is not parsed.

If no localized message is found this message will be used.

Localization

<error_code> and <error_parameters> support localization.

<error_code>

<error_code> is optional unless <error_parameters> is provided.

<error_code> ::= <string>

 

This key is used to find a localized message.

<error_parameters>

<error_parameters> is optional.

<error_parameters ::=
   ( <literal> | <bean_property> | <function> ) ( "," ( <literal> | <bean_property> | <function> ) )*

If error parameters are provided localized messages will be parsed before being displayed. {0} corresponds to the first parameters, {1} to the second and so on.

Customizations

Custom functions

Users can register custom functions to extend the functionality of the parser. This allows extending the functionality of the validator with user code.

To write a custom function extend org.springmodules.valang.function.AbstractFunction. Custom functions must implement the sole constructor of AbstractFunction. The doGetResult function must be implemented.

public class MyFunction extends AbstractFunction {
   public MyFunction(Function[] arguments, int line, int column) {
      super(arguments, line, column);
      definedExactNumberOfArguments(1);
   }
   public Object doGetResult(Object target) {
      return null;
   }
}

Customize date parser

To add a custom date format to the date parser users must provide a regular expression that matches the date format and a date format.

The regular expression must only match the date format. Providing a regular expression that is not sufficiently strict may cause the date parser to stop working properly.

<bean id="myValidator" class="org.springmodules.validation.valang.ValangValidator">
   <property name="valang">
      <value><![CDATA[

&nbsp;&nbsp;&nbsp;&nbsp; { firstName : length(?) < 30 : 'First name too long' }
&nbsp;&nbsp;&nbsp;&nbsp; { lastName : length(?) < 50 : 'Last name too long' }
      ]]></value>
   </property>
   <property name="dateParserRegistrations">
      <map>
         <entry key="^\\d{2}:\\d{2} \\d{8}$" value="HH:mm yyyyMMdd">
      </map>
   </property>
</bean>

Site running on a free Atlassian Confluence Open Source Project License granted to Spring Framework. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.5 Build:#811 Jul 25, 2007) - Bug/feature request - Contact Administrators