JSF Page Rendering After Validation Failure

The way JSF components render themselves depends on if validation had failed or not. This article will explain this subtle difference in behavior.

Consider the simple managed bean:

@ManagedBean
public class Controller {
    Logger logger = Logger.getLogger("TestWeb");
    @Size(min=3)
    private String name;
    private int age;

    public String updateCustomer() {
        logger.info("Updating " + name);

        return null;
    }

    public void prepareRender() {
        name = "Please enter a name";
        age = 0;
    }
    //getters and setters...
}

And the view:

<f:metadata>
    <f:event listener="#{controller.prepareRender()}" type="preRenderView"/>
</f:metadata>

<body> 
<h:messages />
<h:form>
  Name: <h:inputText value="#{controller.name}"/><br/>
  Age: <h:inputText value="#{controller.age}"/><br/>
  <h:commandButton value="Update" action="#{controller.updateCustomer()}"/>
</h:form>
</body>

Lifecycle After Valid Input Submission

Let us say that a user enters valid input (name: John Smith, age: 12) and submits the form. The lifecycle of the request will go as follows.

1. Restore View Phase – This phase completes as usual. Nothing special to discuss.

2. Apply Request Values Phase – User’s input is collected from the POST request parameters and stored with each UI component. Since all inputs are valid, no conversion error occurs at this point and no error message is queued.

3. Process Validation Phase – Each UI component validates the input. Since all inputs are valid, no error message is queued.

4. Update Model Values Phase – In this phase, the name and age properties of the Controller managed bean are updated with the user’s input as it was stored by the UI components in phase #2. As a result, name becomes “John Smith” and age becomes 12.

5. Invoke Application Phase – In this phase, the updateCustomer() method of the managed bean is invoked. The log message prints out the name as “Updating John Smith”.

6. Render Response Phase – First, the prepareRender() method of the managed bean is called, since, it is setup as a pre-render listener. This method resets the model properties. For example, name is set to “Please enter a name”. Next, each UI component renders itself. They grab the data to be output from the model. This is the crucial fact and will play a role later. So, the name text box shows “Please enter a name” and the age text box shows 0.

Lifecycle After Invalid Input Submission

Let us say that a user submits invalid input. Let’s consider two cases:

Case #1: Name is left empty. Age is 12.
Case #2: Name is “John Smith” and age is “abc”.

The lifecycle of the request will go as follows.

1. Restore View Phase – This phase completes as usual. Nothing special to discuss.

2. Apply Request Values Phase – User’s input is collected from the POST request parameters and stored with each UI component. Some invalid input can cause conversion failure. For example, in case #2, conversion will fail for the age text box. In that case, an error message will be queued. Note, a UI component will store input value even if conversion fails. So, in case #2, the age text box component will store “abc”. Lifecycle will proceed to the next phase, even if there was a conversion error.

3. Process Validation Phase – Each UI component validates the input. In case #1, validation will fail for the name text box. For each validation rule violation, an error message is queued.

4. Update Model Values Phase – Since, either conversion or validation had failed, this phase will be skipped. So, the name variable of the managed bean will remain null. And, age will remain 0.

5. Invoke Application Phase – Since, either conversion or validation had failed, this phase will be skipped.

6. Render Response Phase – First, the prepareRender() method of the managed bean is called. This will set the name variable to “Please enter a name”. Next, each UI component renders itself. Now, here is the twist. Instead of grabbing the data to be output from the model, the components will use the input that they had saved in Apply Request Values phase. That means:

For case #1: Name will be empty. Age will be 12.
For case #2: Name will be “John Smith”. Age will be “abc”.

Note, at the time of rendering, the name property is set to “Please enter a name” and age is 0. But, the UI components will ignore that and instead render the actual input entered by the user. So, the work done by prepareRender() is completely wasted. In real life, if the pre-render listener does any kind of database query, you may want to optimize that by skipping the work incase of a validation or conversion error.

public void prepareRender() {
    if (FacesContext.getCurrentInstance().isValidationFailed() == false) {
        name = "Please enter a name";
        age = 0;
    }
}

One thought on “JSF Page Rendering After Validation Failure

  1. Thanks for this very clear explanation!

    But how do I get rid of this behaviour?
    e.g. I want the field where the validation failed to be empty for the user to input a correct value.

    In my specific case I have 1 username and 1 password input. Both with @NotEmpty.
    If one of those (say the password) is not filled, the validation fails and a message is shown (as it should).
    Now I delete the username and type in a password.
    The validation fails because the username is empty. It cleans the password field and displays a message for the username. But now the error happens: the former entered username reappeares!
    How can I prevent this behaviour?

    I use JSF 2.1 and RichFaces 4.2.3

    Greetings from Germany,
    Kevin

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.