ExpressionValidator TipsFieldname referencesAs 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 referencesIf 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"
ExpressionValidators use OGNLOGNL: 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: False expressions trigger the validation errorI 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-lineAs 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 debuggingA 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 equalitynulls 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 These two are equivalent: password.equals(passwordVerified) ... is equivalent to ... password == passwordVerified From the OGNL docs:
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 reloadingDuring 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.
Letter-based comparison operators are your friendsthe problem Won't work field > 2 ...because the greater-than sign has special meaning in XML. the solution This will work field &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).
|