Hello,
recently I was looking for a solution to validate data from AJAX requests (that may send only one single data member belonging to a complete domain object) utilizing the commons validator from spring-modules-validation in order to be able to declaratively define validation rules.
Suppose you have the simple situation with the following two cases:
1st: You have a sign up form, where a user can fill in its complete master data.
2nd: You have a page, where a user can change its master data for every single field, using an ajax request for each field.
For the 1st case we have defined the validation rules inside a form-Tag of the xml file containing the rules.
For the 2nd case we do not want to validate the whole domain object, rather a single field only. Actually I could not find a solution to reuse the validation constraints already defined in the XML-file.
So now I come up with an own solution, which may be useful for others, as well. My solution is driven by the following solution to validate AJAX requests, which only allows the use of the springframework's validator.
http://today.java.net/pub/a/today/20...g-and-dwr.html
For my approach, I had to add some code to some sources from the package org.springmodules.validation.commons:
- DefaultValidatorFactory
- AbstractBeanValidator
Moreover I added one file: ConfigurableBeanFieldValidator
An example follows, how I utilized this new type of validator:
A validator utilizing the new ConfigurableBeanFieldValidator:
Code:
public class UserValidator extends ConfigurableBeanFieldValidator{
private UserManagement usrManagement; //Service used to access persistent domain object
public void setUsrManagement(UserManagement usrManagement) {
this.usrManagement = usrManagement;
}
public boolean supports(Class clazz) {
return User.class.isAssignableFrom(clazz);
}
//Std validation method, which will validate the whole object by
//invoking the commons validator and then the customized validation
//method(s).
public void validate(Object target, Errors errors) {
EcUserVo castTarget = (User)target;
super.validate(target, errors);
validateEmail(castTarget, errors);
validateUsername(castTarget, errors);
}
public void validateEmail(User objToValidate, Errors errors){
//If the commons validator has already detected an error, peristent
//access is not required
if(!errors.hasFieldErrors("email")){
if(usrManagement.loadByEmail(objToValidate.getEmail())!=null){
errors.rejectValue("email", "errors.unique", "The mail address is already in use!");
}
}
}
public void validateUsername(User objToValidate, Errors errors){
if(!errors.hasFieldErrors("username")){
if(usrManagement.loadByUsername(objToValidate.getUsername())!=null){
errors.rejectValue("username", "errors.unique", "The name is already in use!");
}
}
}
}
Remember the two cases described above; For the first case the UserValidator's validate method will do the job of validating the whole form, using the commons validator, as well as the programmatically defined good-old spring validations (methods validateEmail() and validateUsername()).
For the 2nd case the ConfigurableBeanFieldValidator provides a method with the following signature: Errors invokeFieldValidation(String fieldName, Object domainObject). This method firstly validates the field using the commons validator, and secondly validates it using the appropriate method, which name is composed of the word 'validate', concatenated with the capitalized fieldname. The latter method invokation is only done if it exists. The spring bean configuration of the example validator looks as follows:
Code:
<bean id="validatorFactory" class="org.springmodules.validation.commons.DefaultValidatorFactory">
<property name="validationConfigLocations">
<list>
<value>WEB-INF/gen-validator-rules.xml</value>
<value>WEB-INF/my-own-validation-rules.xml</value>
</list>
</property>
</bean>
<bean id="userValidator" class="com.myComp.validators.UserValidator">
<property name="validatorFactory">
<ref local="validatorFactory"/>
</property>
<property name="formName"><value>stduser</value></property>
<property name="usrManagement" ref="userManagement"/>
</bean>
I attached the code of the springmodules classes.
Regards
Thomas