ExpressionValidator Tips

Fieldname references

As long as your Action provides a "setter" and a "getter" for your form fields, you can simply refer to them in your expression by name.

Given this form field:

<input type=text name="foo">

And this Action fragment

private String foo;
public void setFoo(String Foo) { this.foo = foo; }
public String getFoo() {return foo; }

Your form fields are available to your expression like this:

foo == "sometext"

Advanced field references

If you expose an object in your Action via a getter, you can directly set (from the form) and access (from the validation expression) properties within that object.

Given this form fragment:

<input type=text name="address.firstName">
<input type=text name="address.lastName">

And this Action fragment:

private Address address;
public void setAddress(Address address) { this.address = address; }
public Address getAddress() {return address; }

Your validation expression can do this:

address.firstName == "Joe" and address.lastName == "Bloe"

Some use this feature to expose their "model" or "domain" objects directly to their forms and to their validation code.

This can be incredibly powerful but should be used with caution as it allows anybody monkey-ing with URL's (or custom forms) to inject data directly into your domain objects that you might not want to have there.

Jason said it well: "It's a great tool, but it's a sharp tool, and you can cut yourself with it."

ExpressionValidators use OGNL

OGNL: Pronounced like the "ogonal" part of orthogonal.

The ExpressionValidator expressions are simply OGNL expressions that evaluate to true or false. You have the complete OGNL language and stack available to you when writing ExpressionValidator expressions.

For most of what you probably want to do, you don't need to worry about all that. Just reference your fields by name, use standard comparison operators, etc.

But if you want the full meal deal there is a huge amount of power (and complexity) available if you want to take the time to plumb the depths of OGNL. The OGNL docs are here:

http://www.ognl.org/

False expressions trigger the validation error

I often find myself thinking of my validation tests exactly opposite of how WebWork thinks of them.

If you want to trigger a validation error if two fields are inequal, you might be inclined to do this:

Probably not what you want!
email != emailVerified

That will do exactly the opposite of what you expect. It will return "false" when the fields are equal (and trigger a validation error) and "true" when the fields are not equal (not triggering a validation error).

You want to do this:

Probably what you want
email == emailVerified

If your brain works like mine, you'll probably end up negating a lot of your expressions. If you have long or compound expressions that evaluate to true, just wrap the whole thing in parenthesis to negate it:

!
(
  ( chosenAddressId.intValue() eq -1 )
  and
  ( regionId.intValue() eq -1 )
  and
  ( ( countryId.intValue() eq 1 ) or ( countryId.intValue() eq 2 ) )
)

Expression can be multi-line

As you can see above, your expression can span as many lines as you like. This really helps keep complex expressions readable.

Use the validation message for debugging

A common mistake is to incorrectly refer to the field you want to compare. You can verify that the field you think you're referring to is the field you're actually referring to by creating an ExpressionValidator that always returns false (meaning that it always triggers a validation error), and emitting the field values in its message like so:

<field name="user.password_confirm">
  <field-validator type="fieldexpression">
    <param name="expression">false</param>
    <message>${password}   ${password_verified}</message>
  </field-validator>
</field>

Special handling of null and String equality

nulls
The comparison operators used by the ExpressionValidator will internally handle nulls and, generally, "do the right thing" with regard to comparisons containing fields with null values. Recall that in java you might be inclined to write a test like so...

What you'd do in Java
if( field != null && field.intValue() == 2 )

...to ensure your field wasn't null so you avoid a potential null-pointer exception in the rest of the test. This is unnecessary in OGNL, simply do this:

What you do in an ExpressionValidator
field.intValue() == 2

Strings
There is also no need to do .equals() comparisons on strings. Recall that in Java you usually do not compare two strings with the == operator, you use the .equals() method of your String object instead. But the OGNL expression language will automatically do a .equals() comparison for you when you use the == operator on two Strings.

These two are equivalent:

password.equals(passwordVerified)

... is equivalent to ...

password == passwordVerified

From the OGNL docs:

Equality is tested for as follows. If either value is null, they are equal if and only if both are null. If they are the same object or the equals() method says they are equal, they are equal. If they are both Numbers, they are equal if their values as double-precision floating point numbers are equal. Otherwise, they are not equal. These rules make numbers compare equal more readily than they would normally, if just using the equals method.

FieldValidators do not short-circuit ExpressionValidators.

Ever.

See the docs (currently only available on the Wiki docs) for information about short-circuiting:

http://wiki.opensymphony.com/display/XW/Validation+Framework

The upshot is that a FieldValidator (regardless of whether you use the <validator> or <field-validator> syntax) will never short-circuit an ExpressionValidator. And since most of the built-in validators are FieldValidators, you probably will not get the short-circuit behavior you want by mixing FieldValidators and Expressionvalidators.

Given this example...

<validator type="required" short-circuit="true">
    <param name="fieldName">bar</param>
    <message>You must enter a value for bar.</message>
</validator>

<validator type="expression">
    <param name="expression">foo gt bar</param>
    <message>foo must be great than bar.</message>
</validator>

...the ExpresionValidator will always run.

If you find yourself needing to short-circuit a FieldValidator you can always create an ExpressionValidator that does the equivalent work of the FieldValidator. Once your validation check is implemented as an ExpressionValidator it will be short-circuited by other validators.

ExpressionValidators do short-circuit FieldValidators.

An ExpressionValidator will short-circuit FieldValidators.

If we rewrite the above example to place the short-circuit on the ExpressionValidator...

<validator type="required">
    <param name="fieldName">bar</param>
    <message>You must enter a value for bar.</message>
</validator>

<validator type="expression" short-circuit="true">
    <param name="expression">foo gt bar</param>
    <message>foo must be great than bar.</message>
</validator>

... we get behavior wherein a validation error by the ExpressionValidator will cause the "required" FieldValidator to be skipped.

Turn on XML reloading

During development/debugging of expressions, it can be immensely helpful to turn on XML reloading. This will allow your changes to the -validation.xml files be noticed by WebWork without a restart.

In webwork.properties set...

webwork.configuration.xml.reload = true

See the docs about the webwork.properties file and where it should be placed.

Note that if your development environment has you editing your "main" code files in one place and then copying them into your app-server for deployment xml.reload only reloads the deployed copies.

That's a no-duh, but it's easy to forget in IDE's like NetBeans. NetBeans maintains the "main" code in a separate directory from the code actually used by the deployed app (which it locates in the build directory).

If this is the case with your dev environment, no worries, just edit the deployed -validation.xml file while you're developing and debugging and then copy the final changes back to your "main" file when you're done.

Be sure to copy those changes back to your main file before you rebuild!!

Letter-based comparison operators are your friends

the problem
Many of the normal comparison operators cannot be used un-escaped in your XML validation file. For example, you can't use an expression like this...

Won't work
field > 2

...because the greater-than sign has special meaning in XML.

the solution
Some would suggest you escape the greater-than sign like this:

This will work
field &amp;gt; 2

Others have suggested that you use a CDATA block like this (note, I have not personally tried this):

This will also work
<![CDATA[ field > 2 ]]>

But I find both of those rather ugly. The easier thing to do is to just remember that all of the OGNL comparison operators have letter-based notations. So the above (within an ExpressionValidator) works perfectly well:

This will work, and look how pretty it is
field gt 2

The letter-based notation for each of the OGNL comparison operators can be found in this section of the OGNL docs:

http://www.ognl.org/2.6.7/Documentation/html/LanguageGuide/apa.html#operators

I've gotten into the habit of using letter-based operator syntax for all my OGNL comparison operators whether they need to be escaped or not. Keeps my brain in the "OGNL" groove (and helps remind this is not java and that there are some subtle differences such as the null and String handling noted above).

OGNL's letter-based comparison operators feel comfortingly perl-ish. But remember that OGNL's letter-based comparison operators work on all datatypes, unlike perl where the letter-based comparison operators work only on strings.