Implement Business Validation in JavaServer Faces (JSF)

By Jeff Szeto

Introduction

JavaServer Faces (JSF) comes with a standard type conversion and validation framework that can be used for implementing validation logic at view layer.  However, such validation framework is often being misused and this article describes such common pitfall of JSF Validation framework and also provides recommendations of how to implement business related validation in JSF.

Common Pitfall of Using JSF Validation

In JSF, validation framework is already in place so you can do something like (validate an integer input field):

<h:inputText id="purchaseAmount" value="#{bean.purchaseAmount}">
     <f:validateLongRange />
</h:inputText>

It is convenient since validation process is part of the JSF life cycle; if the input value passes validation, the request value will be automatically converted and bind to a model value.

However, such validation model can easily be misused and completely diminish separation between business model and view (MVC pattern violation).  Consider the following example:

<h:inputText id="purchaseAmount" value="#{bean.purchaseAmount}">
     <f:validateLongRange maximum="#{bean.creditLimit}" />
</h:inputText>

In this example, we use the "maximum" attribute to validate whether the input value (purchase amount) is less than maximum value (credit limit) returned by ${bean.creditLimit}.  This seems to be very logical approach since we are using out-of-the-box feature to perform validation.  However, it also violates separation of business model and view layers and also code becomes more difficult to maintain and minimizes reuse.  Consider this, if there is a requirement change that needs the same validation on value fed from a web service, there is no way this view layer validation cannot be reused there.  The worst is that, since this validation logic is not modularized, any requirement changes to this particular validation would be a maintenance nightmare.

Well, keep in mind that the above example is just to illustrate the concept; it certainly doesn't take much to implement a maximum value validation elsewhere.  But the idea here is that, consider if someone actually implements a JSF Validator that performs more complex business logic (e.g. also validate purchaseAmount is greater than freeshippingAmount and less than storecreditAmount...), nobody wants to re-implement that same logic and maintain it on multiple places.

So you may think, "do you mean we should not be using the JSF validation framework at all?"  No, JSF validation framework is a great tool since it also provides automatic data type conversion as well as value binding to a managed bean if validation passes.  But what you should limit yourself from using framework is that, it should only be used for validating input data format such as numeric type, currency and date.  Nothing should go beyond that.  

So where should we implement the business related validation logic in JSF?

Implement Business Related Validation in JSF

Assuming you have followed the best practice to separate business logic in domain layer and user interfaces in view layer, you have 3 options to implement business related validation in JSF:

1. Validate Before Execute

This option is nothing but to execute validation before the intended business logic.  For example, let's say you have a button's action bind to a backing bean's method called "purchase()".  This purchase() method is used for initiating a purchase process.  Inside the purchase() method, you will first perform business related validation against the input value (e.g. purchaseAmount) before execute the purchase logic.  If validation fails, you can add a FacesMessage to the current FacesContext for an error display:

<h:inputText value="#{bean.purchaseAmount}"/>
...
<h:commandButton action="#{bean.purchase}"/>
...


public void purchase() {
    ...
    // validate values first
    if (!order.validatePurchaseAmount(getPurchaseAmount())) {
        FacesContext.getCurrentInstance().addMessage(new FacesMessage("Purchase Amount is invalid"));
        return "validationFailure";
    }
    ...
    // start execute the purchase logic
    ...
}

The above example is only to illustrate the concept of this option.  A better design is to move the validation inside the purchase() method of the Order object (business layer), and let it throw a proper validation failure exception.  This way we can clearly separate business and UI layers:

public void purchase() {
    // set up the Order domain object
    ...
    // start purchase order
    try {
       order.purchase();
    } catch (OverCreditLimitException e) {
             // validation fails due to purchase amount over credit limit
        FacesContext.getCurrentInstance().addMessage(new FacesMessage(e.getMessage()));
        return "validationFailure";
    }
}

This option is not only easy to understand but also a very logical approach.  The only downside is that, there is no clear structure for developer of how to modularize business validation logic.

2. Validator Method in Backing Bean

The JSF input component comes with a way you can bind a backing bean method to perform pure validation.  Here is an example:

<h:inputText value="#{bean.purchaseAmount}" validator="#{bean.validatePurchaseAmount}"/>

As long as your backing bean method has the same method signature as the JSF

Validator like the following:
public void validatePurchaseAmount(FacesContext context, 
UIComponent inputComponent,
Object value) {
    // do your business validation
    ...
}

One advantage of this option is that it provides a structure to group all the validation logic in a backing bean.  However, it may suffer the same pitfall of being easily misused by putting business logic at the backing bean.

3. JSF Validator

You would implement a customized JSF Validator class that can be reused within your view layer.  However, it is strictly for JSF and not much can be reused if you have other part of the application need the same validation.  Also, a JSF Validator is intended to perform formatting level validation of an user input, it would become quite cumbersome if mixing in any business related logic that requires resources that are not available at the backing bean.  For example, Consider implementing a PurchaseAmountValidator which requires accessing a current user's credit limit, developer will need to somehow figure out how to inject the current user's credit limit into this Validator object.   The bottom line is, this option is not recommended for implementing business validation.

Summary

In this article, we have described the potential pitfall of misusing JSF validation framework that should only be used for formatting validation.  For business related validation, it is important to have a clear separation between business domain and UI layers so validation logic can be properly encapsulated.  In addition, we have recommended 2 ways to implement business related validation: Validate before Execute and Validator Method in Backing Bean.  We also re-emphasized that a customized JSF Validator should only be used for formatting validation.



About the author

Jeff Szeto is a developer and architect with over 15 years of experience in enterprise application development. He is a Sun Certified Java Architect and Programmer and holds a Masters degree in Computer Science from Virginia Tech.

Last Update: 20071223