Friday, December 25, 2009

Validating empty text field using JSF

JSF has a pretty comprehensive support for validations, but it is lack of a validation for an empty field. The built-in “required” property of JSF is not so usable, since it validates empty fields only. If a field has a space in it, JSF will accept it. In most scenarios, when inputting text in a form, a space (or several spaces) is considered to be an empty field. Since JSF doesn’t support “out of the box” validation for empty field, we will write our own Validator that will do the job.

Writing a JSF Validator mainly involves 3 things:

  1. Writing the Validator code by implementing a JSF Validator interface.
  2. Registering Validator in JSF faces-config.xml.
  3. Using the Validator in a JSF page.

In order to write the Validator we have to implement “validate” method of Validator interface. This method will be called automatically by JSF, when we use the Validator in some of our input fields. Our Validator class simply checks that the field value is not empty. If the field is empty a ValidationException is thrown from the Validator. JSF mechanism knows to treat this exception as a validation error, when it checks the form inputs for validation errors. Let’s have a look at the Validator code:

package com.bashan.blog.jsf.validator;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
/**
 * @author Bashan
 */
public class RequiredValidator implements Validator {
  public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
    if (value == null || "".equals(value.toString().trim())) {
      FacesMessage message = new FacesMessage();
      String messageStr = (String)component.getAttributes().get("message");
      if (messageStr == null) {
        messageStr = "Please enter data";
      }
      message.setDetail(messageStr);
      message.setSummary(messageStr);
      message.setSeverity(FacesMessage.SEVERITY_ERROR);
      throw new ValidatorException(message);
    }
  }
}

Note, that the Validator tries to get an attribute named “message” from the component for which it is attached. The “message” attribute should contain a custom error message to show to the user. If “message” attribute is not used, a default error message: “Please enter data” is shown to the user.

Now, let’s register the Validator in JSF faces-config.xml file. This file should be located under the “WEB-INF” directory by default:

<?xml version="1.0" encoding="windows-1255"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config> 
  <validator>
    <validator-id>RequiredValidator</validator-id>
    <validator-class>com.bashan.blog.jsf.validator.RequiredValidator</validator-class>
  </validator>
</faces-config>

You can see in this “faces-config.xml” file the validator id, which is used to call the validator from a JSF page, and the JSF class corresponds to this validator id.

Finally, let’s have a look how this validator is used in a JSF page:

<h:inputTextarea id="someText" value="#{support.message}" styleClass="textarea1" required="true" requiredMessage="Please write something">
  <f:attribute name="message" value="Please write something" />
  <f:validator validatorId="RequiredValidator" />             
</h:inputTextarea>
<div>
  <h:message for="someText" styleClass="error"/>
</div>

This is only a fragment of a JSF page, showing a text area control and a message under it. Note, that the control can be any JSF input like <h:inputText />. Also note for the <f:attribue /> control used for sending a custom message to the Validator. Another important thing worth mentioning, it that the “required” attribute of the <h:inputTextArea /> control is also used with the same error message (using the “requiredMessage” property). One can say, using 2 validations is redundant, and that only the “RequiredValidator” could have been used. This was true, unless JSF mechanism had a problematic issue with empty fields: When field is empty (has no value and no spaces) validators and converters are not invoked. For this reason, both “required” and “RequiredValidtor” are needed to be used.

10 comments:

  1. Nice example of validator, thanks for that. Except that your validator is not triggered if no value is submitted:-(
    Have you succeeded to trigger validator in phase Process Validations if no value was specified for inputText?

    Fekete

    ReplyDelete
  2. This is how JSF behaves: no validation is triggered if field has no value. I believe something was done in JSF2 regarding this issue...

    ReplyDelete
  3. I also facing the problem of trigger validator when value is empty (not blank) ... any way to hack ??? can we extend the JSF required validator to validate empty ???

    ReplyDelete
  4. I think JSF2 handled this issue, but I am not sure.
    Anyway, in cases like this, I usually do all the validation in the action itself.

    ReplyDelete
  5. I found how to force JSF 2 to trigger validation even if value is empty. Setting in web.xml:
    <context-param>
    <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
    <param-value>true</param-value>
    <context-param>

    Source: http://andyschwartz.wordpress.com/2009/07/31/whats-new-in-jsf-2/#validation-empty-fields

    Fekete

    ReplyDelete
  6. tried, but it didn't work for me. the method doesn't even get called. only if there is a space or something else it validates properly. wasted a lot of time to realize this one. would be gr8 to know otherwise.

    ReplyDelete
    Replies
    1. Your validator has to implement org.richfaces.validator.NullValueValidator instead of Validator as there is the following code in UIRichInput.validateInput(FacesContext, UIInput, Object):

      if (validator instanceof NullValueValidator || !isEmpty(newValue)) {
      validator.validate(context, component, newValue);
      }

      kr

      Delete
  7. I meant custom validator. the regular one does get called. but the inbuilt validator works without explicitly specifying like above.

    ReplyDelete
  8. http://stackoverflow.com/questions/6304025/work-around-for-faulty-interpret-empty-string-submitted-values-as-null-in-mojarr?lq=1
    is a post where BalusC addresses this issue.
    see if any of that helps

    ReplyDelete
  9. This is a REAL kludge, but you could do something like this:

    1) When you submit, have a javascript that checks for field empty (element = document.getElementById('myfield').
    2) If it's empty (ex: if (element.value.length == 0), put a known string in it to trigger the validator (ex: element.value = 'blank').
    3) In the validator check for 'blank'.
    4) wipe out 'blank' and present the error message.

    It might work

    ReplyDelete