Using beans as validators in XPages

This article describes how you can create your custom validators by implementing javax.faces.validator.Validator interface. But one problem with this is that you need to create a separate Java class for each validation, for e.g. you would have individual Java classes for validating email, credit card number and so on. And for each Java class you have to add <validator>…</validator> entry in faces-config.xml.

This article on JSF conversion and validation describes how a bean can be used for validation keeping all the validation methods in a single Java class. To do that you use the validator attribute under data section of control properties.

validator Attribute

First create a Java class where all your validations would be stored, say AcmeValidators.

package uk.co.pipalia;

import java.io.Serializable;

public class AcmeValidators implements Serializable {
     // We will define its methods in a moment
}

Now we define its methods which would be used for validation. There are some prerequisites on how the these methods should be defined:

  1. The method should be public
  2. Its signature should take parameters of FacesContext, UIComponent and Object
  3. Its return type should be void

You can name the method anything you want. So our Java class would now look something like this (if we are validating for email):

Update 23-June-2013: Removed line of code facesContext.addMessage(component.getClientId(facesContext), message); as it causes error message to be displayed twice if “Display Errors” control is used. Thanks Oliver.

package uk.co.pipalia;

import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;

public class AcmeValidators implements Serializable {

   private static final long serialVersionUID = 7157377379640149444L;

   // The method we would be using to validate email
   public void validateEmail(FacesContext facesContext, UIComponent component, Object value) {
      // Check if email is valid or not
      if (value.toString().indexOf('@') == -1) {
         // Create message saying that email is invalid
         FacesMessage message = new FacesMessage("Email is invalid.");
         // Throw exception so that it prevents document from being saved
         throw new ValidatorException(message);
      }
   }

}

Now create a managed-bean entry for the above class in faces-config.xml. Keep the scope to view.


   acmeValidators
   uk.co.pipalia.AcmeValidators
   view

To call the validation method set the validator property for control. For e.g.


   
      
   

One caveat here is that our validator will not fire if the field value is blank. So now you can put all your validation methods in a single class and then call on your controls.

Bonus tip: You would probably like to look at Apache Commons Validator which provides validations for email, credit card and more.

Share:

9 thoughts on “Using beans as validators in XPages

  1. Oliver Busse

    Nice one!
    But if you add the message to the FacesContext AND throw a new ValidatorException you will get the message twice if you use the xp:messages control. With the single message control bound to the field everything works fine. So I omitted the addMessage method to get this working even with the messages control.

    Reply
    1. Naveen Maurya Post author

      Thanks Oliver. You were right. In “Display Errors” control it does show the error message twice. I have updated my code.

      Reply
  2. Fernando Rodriguez

    Hi,
    excellent post!!

    I had to add:
    import javax.faces.validator.ValidatorException;
    to throw the exception

    Reply
  3. Fernando Rodriguez

    Thanks for sharing!!

    How could I compare with another field to validate?
    I need to compare value with another field in the xpage, but I can´t get the value of other field

    kind regards

    Reply
  4. Martin Rolph

    Great technique!

    Is there a way to customise the error message per control? e.g. if you have two URL fields the error message would just be URL is Invalid so you wouldn’t know which one

    Reply
    1. Naveen Maurya Post author

      Thanks Martin. As of now I haven’t been able to find a way to attach custom error messages to a field. If I do I surely post an update here.

      Reply
    2. Samir Pipalia

      Hi Martin, thanks for your question. In order to get around this issue you can use component.getClientId(facesContext) and then based on the clientid create custom error message accordingly. Hope this helps.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>