Ajax Form Validation Using Spring and DWR Blog

Version 2


    Validating input is a critical element to almost any non-trivial software application. Regardless of the purpose of the application, its architecture, or the platform on which it will run, it is standard practice to verify that all input is valid before being accepted. In three-tier web applications, the choice must be made to validate user input on either the server, the client, or both. Server-side validation is the industry standard but it requires the user to fill out the form, click Submit, and wait for a page refresh. While the best technical solution, it provides a poor but accepted user experience. Although client-side validation, using JavaScript, provides immediate feedback and an enhanced user experience, it has many disadvantages such as being tedious and error-prone to develop, being hard to test, and leading to fragile code. Inconsistent implementations across different browsers and the fact that a user can disable JavaScript is enough to conclude that client-side validation alone is not sufficient. Although a hybrid approach of performing validation on both the client and server may seem like a good solution on the surface it doesn't take long to realize that the increased development time, duplication of logic, and inevitable maintenance and testing problems quickly outweigh the advantages.

    An ideal solution would be to write your validation logic on the server and then have some way of invoking it directly from the client, giving the appearance of client-side validation. Should some circumstance cause this seemingly client-side validation to not be executed correctly, such as a browser incompatibility or JavaScript being turned off, this mechanism should fail gracefully and allow the traditional server-side validation processing to work as usual. In effect, you would gain all the advantages of the hybrid approach while avoiding its disadvantages and the disadvantages of purely client-side validation.

    With the rise and subsequent acceptance of Ajax, you can now do exactly that. Using what is referred to as Ajax form validation, just after a user finishes filling out an input form field a background process of the browser can transparently transmit the form input value to the server. The server then performs validation of the input values. Should the server determine an input value is invalid, a validation error message is returned to the browser and dynamically displayed next to the invalid form input entry. While some advanced web applications have demonstrated this functionality for a short while, the software has typically been hardwired and custom-coded for each form or for each application.

    This article presents a generic and reusable Ajax form validation design that, by using existing open source components and leveraging your applications' existing validation logic, can easily and quickly be used to Ajax validate every form of your web-based applications. To provide a concrete example, the registration form of the jPetstore sample application, provided by the Spring framework, has been modified. This article outlines the steps taken to modify jPetstore and discusses the design- and implementation-level details.

    Before getting started, it should be noted that this article makes use of the Spring framework and a small amount of Spring and Spring MVC familiarity is assumed. Readers needing additional Spring documentation should see the Resources section. If you are not familiar with Spring, don't panic. Conceptually, all of the information presented applies equally to any web-based MVC framework and it would be trivial to modify the examples provided to work with Struts or JSF, for example.

    Getting Started

    The following steps will guide you through getting the sample code up and running:

    1. Download Spring and its dependencies from the Spring downloads page.
    2. Unzip the downloaded file to a convenient location. This directory will be referred to as SPRING_HOME.
    3. Download a modified jPetstore, which has been modified to include Ajax validation on the user registration page, from the link in the Resources section.
    4. Unzip the modified jPetstore into SPRING_HOME/samples, overwriting the original jpetstore directory.
    5. Build and deploy jPetstore to your application server.
    6. Start the HSQL database needed by jPetstore by going intoSPRING_HOME/samples/jpetstore/db/hsqldb and double-clickingserver.bat.
    7. Start your application server.
    8. Point your browser tohttp://localhost:8080/jpetstore/shop/newAccount.do.

    With the sample application up and running, we can move along and discuss the three components required to perform Ajax validation: the server-side validation infrastructure and logic, an Ajax communication framework to marshal information between the server and client, and the client-side JavaScript used to control the process. Because the use of a server-side validation mechanism is probably the most familiar and because your current or planned application would undoubtedly have some server-side validation, we'll start there.

    Server-Side Validation Using Spring

    The first component needed to incorporate Ajax validation into your web application is a server-side validation framework. Spring, a full-stack Java/J2EE application framework that has gained tremendous popularity, and its validation framework are demonstrated through the jPetstore sample application. Although Spring offers incredibly powerful functionality across the entire spectrum of Java software development, two of Spring's greatest strengths are its simplicity and straightforward design. Input validation is an area that is particularly straightforward. The following jPetstore validation code provides an example of a typical Spring Validator:

    public class AccountValidator implements Validator { ... public void validate(Object obj, Errors errors) { ValidationUtils.rejectIfEmpty(errors, "firstName", \\ "FIRST_NAME_REQUIRED", "First name is required."); ValidationUtils.rejectIfEmpty(errors, "lastName", \\ "LAST_NAME_REQUIRED", "Last name is required."); ValidationUtils.rejectIfEmpty(errors, "email", \\ "EMAIL_REQUIRED", "Email address is required."); ValidationUtils.rejectIfEmpty(errors, "phone", \\ "PHONE_REQUIRED", "Phone number is required."); ValidationUtils.rejectIfEmpty(errors, "address1", \\ "ADDRESS_REQUIRED", "Address (1) is required."); ValidationUtils.rejectIfEmpty(errors, "city", \\ "CITY_REQUIRED", "City is required."); ValidationUtils.rejectIfEmpty(errors, "state", \\ "STATE_REQUIRED", "State is required."); ValidationUtils.rejectIfEmpty(errors, "zip", \\ "ZIP_REQUIRED", "ZIP is required."); ValidationUtils.rejectIfEmpty(errors, "country", \\ "COUNTRY_REQUIRED", "Country is required."); } ... }

    While providing a functional example for a sample application, a major drawback to this approach is that the logic is designed to operate on the entire HTML form. An unfortunate consequence is that validation of an individual form field, required to support Ajax validation, is not possible. With a small amount of refactoring, this drawback can be avoided. The resulting code is:

    ... public void validate(Object obj, Errors errors) { Account account = (Account) obj; validateFirstName(account.getFirstName(), errors); validateLastName(account.getLastName(), errors); validateEmail(account.getEmail(), errors); validatePhone(account.getPhone(), errors); validateAddress1(account.getAddress1(), errors); validateCity(account.getCity(), errors); validateState(account.getState(), errors); validateZip(account.getZip(), errors); validateCountry(account.getCountry(), errors); } ... public void validateFirstName(String firstName, Errors errors) { ValidationUtils.rejectIfEmpty(errors, "firstName", \\ "FIRST_NAME_REQUIRED", "First name is required."); } public void validateLastName(String lastName, Errors errors) { ValidationUtils.rejectIfEmpty(errors, "lastName", \\ "LAST_NAME_REQUIRED", "Last name is required."); } ...

    By casting the parameter obj into an instance of the form backing object and extracting the logic of the originalvalidate() method into separate methods intended to validate a single form field, this seemingly cosmetic refactoring provides a handful of benefits. First, the new code results in a number of short, highly cohesive, easy-to-read methods. The logic to validate the first-name input field is easily and quickly found within the validateFirstName() method instead of being scattered throughout the original long "validate everything" method. Second, this level of organization and structure will pay off should your HTML forms or their validation logic grow in complexity and/or length. Third, and most importantly, because there are methods to validate individual input fields, Ajax validation can now be supported.

    When a form submission is received, Spring's form handling process works by first instantiating an instance of the form backing object. Next, a form input element is bound to the backing object by using reflection to call the appropriate setter method with the form input value passed as an argument. This binding process is repeated for each input element. Finally, with the backing object passed as a parameter, the validate()method on a validator is called. Because an Ajax validation request is not a normal form submission and contains only a form input ID and value, Spring's normal process can't be used and the instantiation and binding must be done "manually." However, instead of invoking the Validator.validate() method, which expects an instance of the form backing object, we will invoke the validation method for an individual field. The following code, located in the AccountValidator class and exposed to the client, performs these manual instantiation, binding, and validation invocation steps:

    /** * Get the validation message for an individual * input field of a model object. * * @param modelObject The object to validate against. * @param formInputId The id attribute of the form input field. * @param formInputValue The input value to be validated. * @return The validation message. */ public String getInputFieldValidationMessage(String formInputId, String formInputValue) { String validationMessage = ""; try { Object formBackingObject = new Account(); Errors errors = new BindException(formBackingObject, "command"); formInputId = formInputId.split("\\.")[1]; // Ignore the preceding "command." portion of the id String capitalizedFormInputId = StringUtils.capitalize(formInputId); // Invoke the set[formInputId] method on the Account instance String accountMethodName = "set" + capitalizedFormInputId; Class setterArgs[] = new Class[] { String.class }; Method accountMethod = formBackingObject.getClass().getMethod(accountMethodName, setterArgs); accountMethod.invoke(formBackingObject, new Object[] { formInputValue }); // Invoke the validate[formInputId] method of the AccountValidator instance String validationMethodName = "validate" + capitalizedFormInputId; Class validationArgs[] = new Class[] { String.class, Errors.class }; Method validationMethod = getClass().getMethod(validationMethodName, validationArgs); validationMethod.invoke(this, new Object[] { formInputValue, errors }); validationMessage = getValidationMessage(errors, formInputId); } catch (Exception e) { // Handle appropriately for your application System.out.println("New code exception: " + e); } return validationMessage; } 

    If getInputFieldValidationMessage were passed aformInputId of username, the preceding code would call setUsername() to bind theformInputValue parameter to a newly instantiated instance of Account. Next,validateUsername would be invoked on theAccountValidator class. Finally, the followinggetValidationMessage() would be used to take advantage of Spring's underlying form validation messaging mechanism and retrieve the actual text that is returned to the browser and presented to the user.

    /** * Get the FieldError validation message from the underlying MessageSource for the given fieldName. * * @param errors The validation errors. * @param fieldName The fieldName to retrieve the error message from. * @return The validation message or an empty String. */ protected String getValidationMessage(Errors errors, String fieldName) { String message = ""; FieldError fieldError = errors.getFieldError(fieldName); if (fieldError != null) { message = messageSource.getMessage(fieldError.getCode(), null, "This field is invalid", Locale.ENGLISH); } return message; } 

    Ajax Using DWR

    Ajax has quickly matured to a state where many open source Ajax frameworks exist. You'll be doing yourself a favor by using one of these frameworks instead of creating your own implementation. Direct Web Remoting (DWR), a java.net project created by Get Ahead, is an outstanding choice. Being easy to use while providing advanced features, DWR is well documented and straightforward to integrate into your application. Well designed, DWR works by dynamically generating JavaScript based on Java classes. Using a servlet and the necessary JavaScript infrastructure, JavaScript calls made in the browser are transparently sent to the server, invoked on the Java class, with the results sent back to the browser and available in JavaScript. Because DWR is well documented, only a brief description of the steps taken to integrate it into the sample application are presented. For a more complete explanation of DWR, I refer you to the design overview and getting startedsections of the project's website.

    The following steps were used to integrate DWR into the sample application:

    1. Download dwr.jar from the project's download page. This article uses version 1.1.4.

    2. Add the downloaded dwr.jar to the sample web applicationlib directory.

    3. Include the following servlet definition and mapping in theweb.xml:

      <servlet> <servlet-name>dwr-invoker</servlet-name> <display-name>DWR Servlet</display-name> <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> ... <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> 
    4. Because the sample application uses the Spring framework for validation logic, we need some way to tell DWR to instantiate the Spring validation bean classes and expose them through JavaScript. Fortunately, DWR provides Spring integration out of the box throughSpringCreators. The DWR configuration file, nameddwr.xml and located in the same directory as web.xml, is as follows:

      <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr> <allow> <create creator="spring" javascript="AccountValidatorJS"> <param name="beanName" value="accountValidator"/> <include method="getFieldInputValidationMessage"/> </create> </allow> </dwr> 

      The file instructs DWR to create a JavaScript object namedAccountValidatorJS. With DWR handling all of the details, when the client calls a JavaScript function on theAccountValidatorJS object, a server-side Java method of the same name is invoked on Spring's instance of theAccountValidator class. This is how server-side logic, in this case validation logic, is exposed to the client through Ajax.

    Controlling the Process with JavaScript

    With the server-side validation logic and Ajax communication framework in place, the third and final component is to modify the web tier to support the Ajax validation process. Each page containing a form that is to be Ajax validated needs to have a small amount of JavaScript infrastructure added. An example of this infrastructure is listed below:

    ... <script type='text/javascript' src='/jpetstore/dwr/engine.js'></script> <script type='text/javascript' src='/jpetstore/dwr/util.js'></script> <script type='text/javascript' src='/jpetstore/dwr/interface/AccountValidatorJS.js'></script> <script language="JavaScript"> // Swallow errors and warnings from DWR; handle appropriately in your app DWREngine.setErrorHandler(null); DWREngine.setWarningHandler(null); function validateAccountInputField(element) { var id = element.id; var value = element.value; AccountValidatorJS.getInputFieldValidationMessage(id, value, { callback:function(dataFromServer) { setInputFieldStatus(element.id, dataFromServer); } }); } function setInputFieldStatus(elementId, message) { var id = "" + elementId + "Error"; document.getElementById(id).innerHTML = message; } </script> ... 

    After including two core DWR scripts on the first two lines, the third line includes the generated AccountValidatorJSproxy object. While the first two scripts will typically be included on any page in which you use DWR, the third line is specific to which server-side Java object you intend to take advantage of and will vary from page to page.

    Next, the the global error and warning handlers are set to null, thereby swallowing all DWR errors and warnings. While acceptable for the purposes of this article, this is obviously not sufficient for enterprise-level software and I strongly suggest a different design for for your production applications.

    The validateAccountInputField() function is the workhorse of the client-side validation. By accepting a reference to the form input element that is to be validated, theAccountValidatorJS proxy object is used to transmit the input field's id and value to the server for validation. Although the syntax is cryptic and hard to read, the third parameter to theAccountValidatorJS.getInputFieldValidationMessage()function instructs DWR to invoke thesetInputFieldStatus() callback function when the response from the server is available. At that time, thesetInputFieldStatus() function performs the dynamic display and update of the on-screen validation message. By appending Error to the element's id, a reference to the span used for visual display is obtained and its innerHTML is updated with the content of the response validation message.

    Finally, validateAccountInputField() needs some way of being invoked when the user alters an input field. This is accomplished by adding an onChange() event listener to each form input you wish to Ajax validate. A snippet from an example form is shown below:

    ... <form action="<c:url value="/shop/newAccount.do"/>" method="post"> ... <TR bgcolor="white"> <TD><font color="red">* </font>First name:</TD> <TD> <spring:bind path="accountForm.account.firstName"> <input type="text" id="<c:out value="${status.expression}"/>" value="<c:out value="${status.value}"/>" onChange="validateAccountInputField(this);" /> <span id="<c:out value="${status.expression}"/>Error" class="error"> <c:out value="${status.errorMessage}"/> </span> </spring:bind> </TD> </TR> ... </form> ... 

    While the use of Spring's form-handling capabilities will be unusual to those not familiar with Spring MVC, the rest is a typical HTML form with a span located next to the input field used to display the validation message. The use of anonChange() event listener will invokevaldiateAccountInputField() when a user changes the value of this input field. Using this to pass a reference of itself to the validateAccountInputFiled()function, the code is generic for every input field and can quickly be added to to all of your forms.

    Figure 1 demonstrates the web tier UI after a user has modified the form. In this particular case, the user filled out the form and subsequently removed all input except for the user ID field. As the user removed the input and the browser focus shifted to a different input, the Ajax validation was invoked and a message indicating that that field was required was dynamically displayed. Of particular interest is the user ID input field, with the dynamic message that that username is not available.

    Display of dynamic validation messages
    Figure 1. Display of dynamic validation messages


    Using the jPetStore sample application, this article discussed and demonstrated a design for a generic and reusable Ajax form validation solution. Using existing open source projects and leveraging your applications validation logic, the development time and complexity required to implement this solution into your applications is minimal. After setting up the necessary infrastructure (and possibly some minor refactoring to existing applications), the largest effort will probably be simply addingonChange() event listeners to the HTML form input elements you'd like to validate via Ajax. While this article made use of the Spring and DWR frameworks, nothing about Ajax or the Ajax validation concepts presented here are tied to any particular tool, framework, or language, and implementations can be created in any way that fits your particular technical or business requirements.