Friday, July 19, 2013

JSF Validating multiple fields using custom validator

Writing custom validator to validate multiple fields in JSF.

JSF supports conversion and validation to separate user interface tasks from business logic. There are several useful ready to use conversion and validation tags bundled with JSF. If the web application need special conversion and validation, JSF provide interfaces to implement you own conversion and validation or you can declare method in the managed bean as the following code.

@ManagedBean
public class MyMBean implements Serializable {
...
...
public void myValidator(FacesContext context, UIComponent uiComponent, Object obj) throws ValidatorException {
   // your validation code
}
...
...
}

Assigning validator to input component in JSF pages.

<h:inputText id="fieldA" value="#{myMBean.fieldA}" validator="#{myMBean.myValidator}"/>

UIComponent and Object in custom validator declaration.
The Object parameter passed from JSF is a reference to input component which assigns this custom validator in its validator attribute (As example above, it refer to fieldA). The value of input component can be read by casting as String class.

String fieldAValue = (String)obj;

To find the value of other fields in the form, you can use UIComponent parameter to find target component and then get its value by using findComponent method as the following code.

UIInput fieldBInput = (UIInput) uiComponent.findComponent("fieldB");
String fieldBValue = (String) fieldBInput.getValue();

Example custom validator to verify changing password from user.
Requirements : Need a form to support user to change their password. User must enter the same password twice to confirm the new one.

Code for JSF form.

<h:form id="frmChangePassword">
   <h:panelGrid columns="3">
 <h:outputText value="New password" />
 <h:inputSecret id="password1" 
     value="#{changePassword.password1}" 
     required="true" 
     requiredMessage="Please enter password"/>
 <h:message for="password1" style="color:red"/>
 <h:outputText value="Confirm password" />
 <h:inputSecret  id="password2" 
     value="#{changePassword.password2}"
     required="true" 
     requiredMessage="Please enter password" 
     validator="#{changePassword.validatePassword}" 
     validatorMessage="Password mismatched!"/>
 <h:message for="password2" style="color:red"/>

 <h:commandButton value="Save" 
     action="#{changePassword.updatePassword}"/>
 <h:commandButton value="Cancel" action="main-page"  immediate="true"/>
 </h:panelGrid>
</h:form>

Code for Managed bean.

@ManagedBean
@ViewScoped
public class ChangePassword implements Serializable {
  private static final long serialVersionUID = 1L;
  private String password1;
  private String password2;

  public String getPassword1() {
     return password1;
  }
  public void setPassword1(String password1) {
     this.password1 = password1;
  }
  public String getPassword2() {
     return password2;
  }
  public void setPassword2(String password2) {
     this.password2 = password2;
  }

  public void validatePassword(FacesContext context, UIComponent uiComponent, Object obj) throws ValidatorException {

     UIInput uiPassword1 = (UIInput)uiComponent.findComponent("password1");
     String password1 = (String)uiPassword1.getValue();
     String password2 = (String)obj;

     if (!password2.equals(password1)) {
          throw new ValidatorException(new FacesMessage("password mismatch"));
     }

  public String updatePassword() {
     String username = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal().getName();
     System.out.println("Changing password for " + username);
     if (password1.equals(password2)) {
          // Do database related tasks;
          return "main-page";

     } else {
          return "change-password-error";
     }

  }
}







1 comment: