5

How would you compare two string for equality in a JSF Validator?

if (!settingsBean.getNewPassword().equals(settingsBean.getConfirmPassword())) {
    save = false;
    FacesUtils.addErrorMessage(null, "Password and Confirm Password are not same", null);
}
Tiny
  • 27,221
  • 105
  • 339
  • 599
c12
  • 9,557
  • 48
  • 157
  • 253

1 Answers1

19

Use a normal Validator on the second component and pass the value of the first component as attribute of the second component.

Thus, so

<h:inputSecret id="password" binding="#{passwordComponent}"
    value="#{bean.password}"
    required="true"
    requiredMessage="Please enter password" 
    validatorMessage="Please enter at least 8 characters">
    <f:validateLength minimum="8" />
</h:inputSecret>
<h:message for="password" />

<h:inputSecret id="confirmPassword" 
    required="#{not empty passwordComponent.value}"
    requiredMessage="Please confirm password"
    validatorMessage="Passwords are not equal">
    <f:validator validatorId="validateEqual" />
    <f:attribute name="otherValue" value="#{passwordComponent.value}" />
</h:inputSecret>
<h:message for="confirmPassword" />

(note that binding on first component is exactly as-is; you shouldn't bind it to a bean property!)

with

@FacesValidator(value="validateEqual")
public class ValidateEqual implements Validator<Object> {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        Object otherValue = component.getAttributes().get("otherValue");

        if (value == null || otherValue == null) {
            return; // Let required="true" handle.
        }

        if (!value.equals(otherValue)) {
            throw new ValidatorException(new FacesMessage("Values are not equal."));
        }
    }

}

If you happen to use the JSF utility library OmniFaces, then you can use <o:validateEqual> for this. This exact case of "confirm password" is demonstrated on <o:validateEqual> showcase.

See also:

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Hi BalusC, is there any other way to do this without binding the inputSecret component? – c12 Apr 03 '11 at 02:58
  • You could hardcode the ID and pass it instead. E.g. `` and then use `UIViewRoot#findComponent()` to get the component. However this is only clumsy. Why the aversion against binding? It doesn't make sense to me. – BalusC Apr 03 '11 at 02:59
  • Isn't there additional overhead (memory wise) when adding bindings for components? Its probably minimal, but just a question. – c12 Apr 03 '11 at 06:35
  • It's very minimal. It's just one more reference to an existing object in memory. Referencing a String is actually potentially more expensive since the value doesn't necessarily already exist in the string pool. – BalusC Apr 03 '11 at 11:07
  • I was just reading about OmniFaces on your blog. It's indeed a lot easier this way : a single tag in the view, and the job is done! I'm only starting to work with JSF, so I will keep homebrewing stuff, but I definitely keep this project in mind. – Med Jan 04 '13 at 16:42
  • When wondering why the validator is not working attach this to the faces-config.xml in the META-INF between the Tag equalsValidator com.yourpackage.EqualsValidator – Pwnstar Jan 11 '17 at 09:17
  • @ImproveAnything That only required when you're still using the jurassic JSF 1.x from nearly a decade ago when configuration annotations weren't that common. – BalusC Jan 11 '17 at 09:19