Struts Validator: Validating Two Fields Match

In the Struts Validator Guide, there is a section on how to create a pluggable validator that matches two fields. I've been using this server-side validator (as shown in the example) to do password/confirm password validation. This has worked great for me, but I've always wanted the Validator to have the client-side JavaScript method for it too. I wrote my own that just compared the two fields, but it's not the same as having one rendered for you (from validator-rules.xml). So yesterday, I did some tinkering and figured out how to add the JavaScript method to validator-rules.xml. So here's how to configure the whole thing (most of this is contained in the Validator Guide, save the JavaScript).

How To Add a TwoFields Validator

Step 1: Create a class with a validateTwoFields method. In my code, my class is ValidationUtil and has the following method:

public static boolean validateTwoFields(Object bean, ValidatorAction va,
                                        Field field, ActionErrors errors,
                                        HttpServletRequest request) {
    String value =
        ValidatorUtil.getValueAsString(bean, field.getProperty());
    String sProperty2 = field.getVarValue("secondProperty");
    String value2 = ValidatorUtil.getValueAsString(bean, sProperty2);

    if (!GenericValidator.isBlankOrNull(value)) {
        try {
            if (!value.equals(value2)) {
                errors.add(field.getKey(),
                           Resources.getActionError(request, va, field));

                return false;
            }
        } catch (Exception e) {
            errors.add(field.getKey(),
                       Resources.getActionError(request, va, field));

            return false;
        }
    }

    return true;
}

Step 2: Edit validator-rules.xml to contain the "twofields" rule.

<validator name="twofields" 
    classname="org.appfuse.webapp.util.ValidationUtil" method="validateTwoFields" 
    methodParams="java.lang.Object,
                  org.apache.commons.validator.ValidatorAction,
                  org.apache.commons.validator.Field,
                  org.apache.struts.action.ActionErrors,
                  javax.servlet.http.HttpServletRequest" 
   depends="required" msg="errors.twofields">
    <javascript><![CDATA[
        function validateTwoFields(form) {
            var bValid = true;
            var focusField = null;
            var i = 0;
            var fields = new Array();
            oTwoFields = new twofields();
            for (x in oTwoFields) {
                var field = form[oTwoFields[x][0]];
                var secondField = form[oTwoFields[x][2]("secondProperty")];
            
                if (field.type == 'text' ||
                    field.type == 'textarea' ||
                    field.type == 'select-one' ||
                    field.type == 'radio' ||
                    field.type == 'password') {
            
                    var value;
                    var secondValue;
                    // get field's value
                    if (field.type == "select-one") {
                        var si = field.selectedIndex;
                        value = field.options[si].value;
                        secondValue = secondField.options[si].value;
                    } else {
                        value = field.value;
                        secondValue = secondField.value;
                    }
                
                    if (value != secondValue) {
                    
                        if (i == 0) {
                            focusField = field;
                        }
                        fields[i++] = oTwoFields[x][1];
                        bValid = false;
                    }
                }
            }
            
            if (fields.length > 0) {
                focusField.focus();
                alert(fields.join('\n'));
            }
            
            return bValid;
        }]]></javascript>
</validator>

Step 3: Configure validation for your form in validation.xml:

<field property="password"
     depends="required,twofields">
  <msg
    name="required"
    key="errors.required"/>
  <msg
    name="twofields"
    key="errors.twofields"/>

  <arg0 key="userForm.password"/>
  <arg1
    key="userForm.confirmPassword"
  />
  <var>
    <var-name>secondProperty</var-name>
    <var-value>confirmPassword</var-value>
  </var>
</field>

Where errors.twofields=The '{0}' field has to have the same value as the '{1}' field. An alternative to Step 3 is to use XDoclet to generate your validation.xml. This requires (1) configuring XDoclet (of course) and (2) adding some @struts tags to your form on the setPassword method.

/**
 * Returns the password.
 * @return String
 *
 * @struts.validator type="required" msgkey="errors.required"
 * @struts.validator type="twofields" msgkey="errors.twofields"
 * @struts.validator-args arg1resource="userForm.password"
 * @struts.validator-args arg1resource="userForm.confirmPassword"
 * @struts.validator-var name="secondProperty" value="confirmPassword"
 */
public String setPassword() {
	return password;
}

I've sent this as a proposal to the struts-dev mailing list yesterday, but haven't heard anything yet. Enjoy!

Update: You'll need to update ValidationUtil.java and validator-rules-custom.xml for Struts 1.2. Full files: ValidationUtil.java and validation-rules-custom.xml.

Posted in Java at Feb 26 2003, 12:29:56 PM MST 10 Comments
Comments:

Oh my god this is painful.... having javascript put in for you is nice and all, but... yuck. Check out the validation stuff I put into Xwork. Combine a quick and simple ExpressionValidator with "password1 == password2" and a template for 2 password fields with some javascript which you can easily turn into a jsp tag like the rest of the ui tags we've got, and you've got a much simpler solution.

Posted by Jason Carreira on February 27, 2003 at 12:14 PM MST #

IMO there's really nothing to it. For the most part, all the validators I've needed have been written in the core validator stuff. This includes server-side and client-side stuff. You guys should look into using the Commons Validator - why re-invent the wheel? You could at least borrow the stuff for client side validation of e-mails, credit cards, regular expressions, etc...

Posted by Matt Raible on February 27, 2003 at 10:48 PM MST #

I need some advice.I develop a program to accept date with the fomrat of MM/dd/yyyy. I have defined the datePattern MM/dd/yyyy in validator.xml. When i run the program and give an input - 04/12/2003 it says that the date validation is FAILED. can anyone help me with this? I think i have provide the right format. tq

Posted by icemankimi on July 08, 2003 at 03:02 AM MDT #

Why reinvent the wheel - I've been using Fortran for over 30 years now and I've never had to.......

Posted by Anon-II on May 04, 2004 at 04:35 PM MDT #

This is really great, Matt.

Posted by John Norman on May 26, 2004 at 06:41 PM MDT #

I am a beginner of struts.Would you show the details of org.appfuse.webapp.util.ValidationUtil.Thanks.

Posted by rainer on July 04, 2004 at 07:25 AM MDT #

Here's the source from AppFuse's CVS: ValidationUtil.java.

Posted by Matt Raible on July 04, 2004 at 03:44 PM MDT #

!If you are using Struts 1.2, this rule can be implemented using the new <code>validwhen</code> Validator rule. {{{ <field property="password2" depends="required,validwhen"> <arg key="prompt.password2"/> <msg name="validwhen" key="error.password.match"/> <var> <var-name>test</var-name> <var-value>(*this* == password)</var-value> </var> </field> }}}

Posted by Bill Siggelkow on July 11, 2004 at 11:14 PM MDT #

Hi, I tried to write custom validation rule called "identical". But, if I give oIdentical = new identical(); I didn't get any client side alert messages. Hope this statement doesn't generate necessary javascript code when the rule is configured and executed. I'm using Struts 1.2.1 (Beta). Could you pl tell me the use of oTwoFields = new twofields(); statement and how struts uses this statement to generate client side javascript. Thanx in advance, Ratnakar

Posted by Ratnakar on August 06, 2004 at 07:59 AM MDT #

I took a look at Struts 1.2.4 and while "validwhen" exists, it doesn't have a client-side component. I wasn't aware of "identical", but I'm guessing it's the same scenario.

BTW, I did have to update the above script for 1.2.

Posted by Matt Raible on October 01, 2004 at 08:29 AM MDT #

Post a Comment:
Comments are closed for this entry.