com.opensymphony.xwork2.validator.Validator Maven / Gradle / Ivy
Show all versions of xwork Show documentation
/*
* Copyright (c) 2002-2007 by OpenSymphony
* All rights reserved.
*/
package com.opensymphony.xwork2.validator;
import com.opensymphony.xwork2.util.ValueStack;
/**
*
* The validators supplied by the XWork distribution (and any validators you
* might write yourself) come in two different flavors:
*
*
* - Plain Validators / Non-Field validators
* - FieldValidators
*
*
* Plain Validators (such as the ExpressionValidator) perform validation checks
* that are not inherently tied to a single specified field. When you declare a
* plain Validator in your -validation.xml file you do not associate a fieldname
* attribute with it. (You should avoid using plain Validators within the
* syntax described below.)
*
* FieldValidators (such as the EmailValidator) are designed to perform
* validation checks on a single field. They require that you specify a fieldname
* attribute in your -validation.xml file. There are two different (but equivalent)
* XML syntaxes you can use to declare FieldValidators (see " vs.
* syntax" below).
*
* There are two places where the differences between the two validator flavors
* are important to keep in mind:
*
*
* - when choosing the xml syntax used for declaring a validator
* (either
or )
* - when using the short-circuit capability
*
*
* NOTE:Note that you do not declare what "flavor" of validator you are
* using in your -validation.xml file, you just declare the name of the validator
* to use and Struts will know whether it's a "plain Validator" or a "FieldValidator"
* by looking at the validation class that the validator's programmer chose
* to implement.
*
*
*
*
*
*
* To define validation rules for an Action, create a file named ActionName-validation.xml
* in the same package as the Action. You may also create alias-specific validation rules which
* add to the default validation rules defined in ActionName-validation.xml by creating
* another file in the same directory named ActionName-aliasName-validation.xml. In both
* cases, ActionName is the name of the Action class, and aliasName is the name of the
* Action alias defined in the xwork.xml configuration for the Action.
*
* The framework will also search up the inheritance tree of the Action to
* find validation rules for directly implemented interfaces and parent classes of the Action.
* This is particularly powerful when combined with ModelDriven Actions and the VisitorFieldValidator.
* Here's an example of how validation rules are discovered. Given the following class structure:
*
*
* - interface Animal;
* - interface Quadraped extends Animal;
* - class AnimalImpl implements Animal;
* - class QuadrapedImpl extends AnimalImpl implements Quadraped;
* - class Dog extends QuadrapedImpl;
*
*
* The framework method will look for the following config files if Dog is to be validated:
*
*
* - Animal
* - Animal-aliasname
* - AnimalImpl
* - AnimalImpl-aliasname
* - Quadraped
* - Quadraped-aliasname
* - QuadrapedImpl
* - QuadrapedImpl-aliasname
* - Dog
* - Dog-aliasname
*
*
* While this process is similar to what the XW:Localization framework does
* when finding messages, there are some subtle differences. The most important
* difference is that validation rules are discovered from the parent downwards.
*
*
* NOTE:Child's *-validation.xml will add on to parent's *-validation.xml
* according to the class hierarchy defined above. With this feature, one could have
* more generic validation rule at the parent and more specific validation rule at
* the child.
*
*
*
*
*
* There are two ways you can define validators in your -validation.xml file:
*
* - <validator>
* - <field-validator>
*
* Keep the following in mind when using either syntax:
*
* Non-Field-Validator
* The <validator> element allows you to declare both types of validators
* (either a plain Validator a field-specific FieldValidator).
*
*
*
*
* <!-- Declaring a plain Validator using the <validator> syntax: -->
*
* <validator type="expression>
* <param name="expression">foo gt bar</param>
* <message>foo must be great than bar.</message>
* </validator>
*
*
*
*
*
* <!-- Declaring a field validator using the <validator> syntax; -->
*
* <validator type="required">
* <param name="fieldName">bar</param>
* <message>You must enter a value for bar.</message>
* </validator>
*
*
*
*
*
* field-validator
* The <field-validator> elements are basically the same as the <validator> elements
* except that they inherit the fieldName attribute from the enclosing <field> element.
* FieldValidators defined within a <field-validator> element will have their fieldName
* automatically filled with the value of the parent <field> element's fieldName
* attribute. The reason for this structure is to conveniently group the validators
* for a particular field under one element, otherwise the fieldName attribute
* would have to be repeated, over and over, for each individual <validator>.
*
* HINT:
* It is always better to defined field-validator inside a <field> tag instead of
* using a <validator> tag and supplying fieldName as its param as the xml code itself
* is clearer (grouping of field is clearer)
*
* NOTE:
* Note that you should only use FieldValidators (not plain Validators) within a
* block. A plain Validator inside a <field> will not be
* allowed and would generate error when parsing the xml, as it is not allowed in
* the defined dtd (xwork-validator-1.0.2.dtd)
*
*
*
*
* Declaring a FieldValidator using the <field-validator> syntax:
*
* <field name="email_address">
* <field-validator type="required">
* <message>You cannot leave the email address field empty.</message>
* </field-validator>
* <field-validator type="email">
* <message>The email address you entered is not valid.</message>
* </field-validator>
* </field>
*
*
*
*
*
* The choice is yours. It's perfectly legal to only use elements
* without the elements and set the fieldName attribute for each of them.
* The following are effectively equal:
*
*
*
*
* <field name="email_address">
* <field-validator type="required">
* <message>You cannot leave the email address field empty.</message>
* </field-validator>
* <field-validator type="email">
* <message>The email address you entered is not valid.</message>
* </field-validator>
* </field>
*
*
* <validator type="required">
* <param name="fieldName">email_address</param>
* <message>You cannot leave the email address field empty.</message>
* </validator>
* <validator type="email">
* <param name="fieldName">email_address</param>
* <message>The email address you entered is not valid.</message>
* </validator>
*
*
*
*
*
* It is possible to short-circuit a stack of validators.
* Here is another sample config file containing validation rules from the
* Xwork test cases: Notice that some of the <field-validator> and
* <validator> elements have the short-circuit attribute set to true.
*
*
*
* <!-- START SNIPPET: exShortCircuitingValidators -->
* <!DOCTYPE validators PUBLIC
* "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
* "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
* <validators>
* <!-- Field Validators for email field -->
* <field name="email">
* <field-validator type="required" short-circuit="true">
* <message>You must enter a value for email.</message>
* </field-validator>
* <field-validator type="email" short-circuit="true">
* <message>Not a valid e-mail.</message>
* </field-validator>
* </field>
* <!-- Field Validators for email2 field -->
* <field name="email2">
* <field-validator type="required">
* <message>You must enter a value for email2.</message>
* </field-validator>
* <field-validator type="email">
* <message>Not a valid e-mail2.</message>
* </field-validator>
* </field>
* <!-- Plain Validator 1 -->
* <validator type="expression">
* <param name="expression">email.equals(email2)</param>
* <message>Email not the same as email2</message>
* </validator>
* <!-- Plain Validator 2 -->
* <validator type="expression" short-circuit="true">
* <param name="expression">email.startsWith('mark')</param>
* <message>Email does not start with mark</message>
* </validator>
* </validators>
* <!-- END SNIPPET: exShortCircuitingValidators -->
*
*
*
* short-circuiting and Validator flavors
* Plain validator takes precedence over field-validator. They get validated
* first in the order they are defined and then the field-validator in the order
* they are defined. Failure of a particular validator marked as short-circuit
* will prevent the evaluation of subsequent validators and an error (action
* error or field error depending on the type of validator) will be added to
* the ValidationContext of the object being validated.
*
* In the example above, the actual execution of validator would be as follows:
*
*
* - Plain Validator 1
* - Plain Validator 2
* - Field Validators for email field
* - Field Validators for email2 field
*
*
* Since Plain Validator 2 is short-circuited, if its validation failed,
* it will causes Field validators for email field and Field validators for email2
* field to not be validated as well.
*
* Usefull Information:
* More complicated validation should probably be done in the validate()
* method on the action itself (assuming the action implements Validatable
* interface which ActionSupport already does).
*
*
* A plain Validator (non FieldValidator) that gets short-circuited will
* completely break out of the validation stack. No other validators will be
* evaluated and plain validators takes precedence over field validators meaning
* that they get evaluated in the order they are defined before field validators
* get a chance to be evaluated.
*
*
*
*
*
* Short cuircuiting and validator flavours
* A FieldValidator that gets short-circuited will only prevent other
* FieldValidators for the same field from being evaluated. Note that this
* "same field" behavior applies regardless of whether the or
* syntax was used to declare the validation rule.
* By way of example, given this -validation.xml file:
*
*
*
*
* <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>
*
*
*
*
* both validators will be run, even if the "required" validator short-circuits.
* "required" validators are FieldValidator's and will not short-circuit the plain
* ExpressionValidator because FieldValidators only short-circuit other checks on
* that same field. Since the plain Validator is not field specific, it is
* not short-circuited.
*
*
*
*
* As mentioned above, the framework will also search up the inheritance tree
* of the action to find default validations for interfaces and parent classes of
* the Action. If you are using the short-circuit attribute and relying on
* default validators higher up in the inheritance tree, make sure you don't
* accidentally short-circuit things higher in the tree that you really want!
*
* The effect of having common validators on both
*
*
* - <actionClass>-validation.xml
* - <actionClass>-<actionAlias>-validation.xml
*
*
* It should be noted that the nett effect will be validation on both the validators available
* in both validation configuration file. For example if we have 'requiredstring' validators defined
* in both validation xml file for field named 'address', we will see 2 validation error indicating that
* the the address cannot be empty (assuming validation failed). This is due to WebWork
* will merge validators found in both validation configuration files.
*
*
* The logic behind this design decision is such that we could have common validators in
* <actionClass>-validation.xml and more context specific validators to be located
* in <actionClass>-<actionAlias>-validation.xml
*
*
*
*
*
* Validator's validation messages could be internatinalized. For example,
*
* <field-validator type="required">
* <message key="required.field" />
* </field-validator>
*
* or
*
* <validator type="expression">
* <param name="expression">email.startsWith('Mark')</param>
* <message key="email.invalid" />
* </validator>
*
* In the first case, WebWork would look for i18n with key 'required.field' as the validation error message if
* validation fails, and 'email.invalid' in the second case.
*
* We could also provide a default message such that if validation failed and the i18n key for the message
* cannot be found, WebWork would fall back and use the default message. An example would be as follows :-
*
* <field-validator type="required">
* <message key="required.field">This field is required.</message>
* </field-validator>
*
* or
*
* <validator type="expression">
* <param name="expression">email.startsWith('Mark')</param>
* <message key="email.invalid">Email needs with starts with Mark</message>
* </validator>
*
*
*
*
* @author Jason Carreira
*/
public interface Validator {
/**
* Sets the default message to use for validation failure
*
* @param message the default message
*/
void setDefaultMessage(String message);
/**
* Gets the default message used for validation failures
*
* @return the default message
*/
String getDefaultMessage();
/**
* Gets the validation failure message for the given object
*
* @param object object being validated (eg. a domain model object)
* @return the validation failure message
*/
String getMessage(Object object);
/**
* Sets a resource bundle key to be used for lookup of validation failure message
*
* @param key the resource bundle key
*/
void setMessageKey(String key);
/**
* Gets the resource bundle key used for lookup of validation failure message
*
* @return the resource bundle key
*/
String getMessageKey();
/**
* Sets the messsage parameters to be used when parsing i18n messages
*
* @param messageParameters the messsage parameters
*/
void setMessageParameters(String[] messageParameters);
/**
* Gets the messsage parameters to be used when parsing i18n messages
*
* @return the messsage parameters
*/
String[] getMessageParameters();
/**
* This method will be called before validate with a non-null ValidatorContext.
*
* @param validatorContext the validation context to use.
*/
void setValidatorContext(ValidatorContext validatorContext);
/**
* Gets the validation context used
*
* @return the validation context
*/
ValidatorContext getValidatorContext();
/**
* The validation implementation must guarantee that setValidatorContext will
* be called with a non-null ValidatorContext before validate is called.
*
* @param object the object to be validated.
* @throws ValidationException is thrown if there is validation error(s).
*/
void validate(Object object) throws ValidationException;
/**
* Sets the validator type to use (see class javadoc).
*
* @param type the type to use.
*/
void setValidatorType(String type);
/**
* Gets the vaildator type used (see class javadoc).
*
* @return the type used
*/
String getValidatorType();
/**
* Sets the value stack to use to resolve values and parameters
*
* @param stack The value stack for the request
* @since 2.1.1
*/
void setValueStack(ValueStack stack);
}