The Seam3 Faces module will support "Cross-field form validation" in it's imminent Alpha3 release. This is your best bet for a minimal code solution, see this blog for a howto.
Alternatively I've done this programmatically by using the f:attribute tag to pass the clientId of another form field to a custom validator, then using the UIComponent passed into the custom validator to access the other filed by id.
Here's the facelet file:
<h:outputLabel value="Enter your email address" rendered="#{!cc.attrs.registration.subRegistration}" />
<h:inputText label="Email" id="textEmail1" value="#{cc.attrs.registration.email}" rendered="#{!cc.attrs.registration.subRegistration}" required="true" maxlength="128" size="35"></h:inputText>
<h:message for="textEmail1" rendered="#{!cc.attrs.registration.subRegistration}"></h:message>
<h:outputLabel value="Re-enter your email address confirmation:" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}" />
<h:inputText label="Email repeat" id="textEmail2" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}" maxlength="64" size="35">
<f:validator validatorId="duplicateFieldValidator" />
<f:attribute name="field1Id" value="#{component.parent.parent.clientId}:textEmail1" />
</h:inputText>
<h:message for="textEmail2" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}"></h:message>
Here's the validator class:
package ca.triumf.mis.trevents.jsf.validator;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
@FacesValidator(value="duplicateFieldValidator")
public class DuplicateFieldValidator implements Validator {
@Override
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
// Obtain the client ID of the first field from f:attribute.
System.out.println(component.getFamily());
String field1Id = (String) component.getAttributes().get("field1Id");
// Find the actual JSF component for the client ID.
UIInput textInput = (UIInput) context.getViewRoot().findComponent(field1Id);
if (textInput == null)
throw new IllegalArgumentException(String.format("Unable to find component with id %s",field1Id));
// Get its value, the entered text of the first field.
String field1 = (String) textInput.getValue();
// Cast the value of the entered text of the second field back to String.
String confirm = (String) value;
// Check if the first text is actually entered and compare it with second text.
if (field1 != null && field1.length() != 0 && !field1.equals(confirm)) {
throw new ValidatorException(new FacesMessage("E-mail addresses are not equal."));
}
}
}