HTTP clients such as browsers send form data to web applications following an event such as a form submission. HTTP does not permit any types other than strings for the key/value pairs representing form data. The resulting form submissions are seen by a server-side application as a set of string objects. This can be a problem for web applications that have more specific requirements on the data. Validation is the process of confirming that form data received from a client conforms to the data format or is within a specific range required by the application.
Examples of validation include the following:
Validation can be performed by clients, such as browsers that provide client-side scripting validation capabilities like the use of JavaScript[TM] technology. Regardless of whether client-side scripting is performed, server-side validation should always be performed.
Validation allows a web application to be more secure. Validation
ensures that the input data received directly from a client is never
used in database commands, in the outgoing HTML response, or
for running shell commands. These techniques are commonly used by
malicious individuals to gain control of the systems on which web
applications
run.
JavaServer[TM] Faces technology provides several ways for a developer as well as a page author to define server side validation using built-in validation as well as customized solutions. This document presents strategies for server-side validation using JavaServer Faces technology.
The solution is to use facilities built into JavaServer Faces technology to provide a server-side form data validation. This document will discuss several strategies that may be used with JavaServer Faces technology which are listed below.
Each strategy is discussed in more detail in this document. The
table below
summarizes the benefits and drawbacks of each strategy.
Strategy | Benefits | Drawbacks |
Built-in validators | Easy for page author to configure. | Limited number of validators provided. |
Custom validators | Easy to add to a UI component. Validation code defined in a single class. | Page author can not configure validation parameters. Java[TM] source must be changed to change validation. |
Custom validators with customizable validation parameters | Easy for page author to configure. Provides fine-grained
configuration of validation parameters used by the custom validator
using a class that extends javax.faces.webapp.ValidatorTag .
Validation
code is essentially turned into components that may be reused. |
Complex for a developer to create (requires knowledge of custom actions, low-level details of JavaServer Faces technology). Java code required to validate input parameters which makes it less customizable. |
Validation using managed beans | Easy for page author to configure. Validation code can be easily defined in a managed bean. Good for coarse grained (application-wide) validation configurable as managed beans. | Page author cannot configure the validation for each UI component. Multiple methods are needed to customize validation code. |
As a developer, choose the best solution based on your usecases and the drawbacks that are detailed in the table above.
To summarize:
JavaServer Faces technology provides a model by which a JavaServer Faces developer or third party could provide an extensive set of validators beyond those provided with the JavaServer Faces implementation. These validators could be provided as a reusable library. Another consideration is to utilize such a library if it fits the needs of your application.
The remainder of this document describes each strategy in more detail.
JavaServer Faces technology provides some built-in validators for doing basic things such as bounds checking on numbers which might be floats, longs, or integer values. These validators are initialized and configured as managed beans.
You should be aware of a subtle side effect of using
the built-in validators.
When a user posts a form that contains at least one validation error,
the view is re-rendered with the error messages displayed.
However, the "Update Model Values" and "Invoke Application"
phases of the JavaServer Faces life-cycle are bypassed, and the
response is rendered
immediately.
Of course this is for a good reason; it would not be good if the
backing beans were
set with values that were determined to be invalid. However, this also
means that if
your backing bean is in the request scope and a validation error
occurs, any value
bindings in your page are skipped and your backing bean is not updated
accordingly. For example, if a hidden text field is bound to a String
property x
in the backing bean, then x
is not updated if there is a
validation error. If other
getters depend on x
being
set, the rendered response might be working
from an incomplete data set.
The following validators are provided with JavaServer Faces technology version 1.1:
Tag Name | Class Name | Description |
<f:validateDoubleRange> | javax.faces.validator.DoubleRangeValidator | Validates ranges with doubles. Good for working with currencies. |
<f:validateLongRange> | javax.faces.validator.LongRangeValidator | Validates ranges that use longs. |
<f:validateLength> | javax.faces.validator.LengthValidator | Validates the length of an form variable. |
There are two ways that a validator can be used. You can define and configure it as a managed bean, or use the corresponding tags to define it.
Following is an example on how a page author would define and configure one of the built-in validation tags:
<h:form id="validatorForm" onsubmit="return client_validation();">
<h:inputText id="bigNumber" value="#{ValidatorBean.bigNumber}">
<f:validateLongRange maximum="11" minimum="5"/>
</h:inputText>
<p>
<h:commandButton id="submit" action="success" value="Submit" />
</p>
<p>
<h:message style="color: orange" id="error3" for="bigNumber"/>
</p>
</h:form>
The subelement of the inputText tag validates a number range. In this case, parameters for the validator are set as attributes (maximum/minimum) of the tag. An invalid number causes the page to be redisplayed with an error message rendered in the location of the <h:message> element.
Built-in validators can provide fine-grained UI component validation. The attributes for the built-in validators can also be set using value bindings. Extending the example, you can also specify the validator as the following:
<f:validateLongRange minimum="#{MyBackingBean.minimum}" maximum="#{MyBackingBean.maximum}" />
In the example above, the range attributes are specified in a backing bean named MyBackingBean.
UI Components can define the required attribute as true
that causes validators to be called even if a null or zero-length
string
value is defined, but the validation code must be capable
of accepting such values. In cases where the required attribute
is not set to true
, validators registered with that UI
Component are
not called.
A built-in validator can also be defined to provide application-wide validation. In this case, the validators are defined and initialized as managed beans. These managed beans can then use method bindings on the validator attribute to validate a UI component's content in the same way you would do with a custom validator method defined in a manged bean. Following is an example of an application-scoped validator managed bean that uses one of the built-in validators.
<managed-bean>
<description>
A Pre-defined JavaServer Faces Long Range Validator
</description>
<managed-bean-name>JSFValidator</managed-bean-name>
<managed-bean-class>javax.faces.validator.LongRangeValidator</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>minimum</property-name>
<property-class>int</property-class>
<value>0</value>
</managed-property>
<managed-property>
<property-name>maximum</property-name>
<property-class>int</property-class>
<value>5</value>
</managed-property>
</managed-bean>
The managed bean definition for JSFValidator uses a built-in range-checking validator which is defined by specifying one of the validators as a managed bean. The minimum and maximum ranges are set on the JSFValidator bean.
<h:form id="validatorForm">
<p>Enter a number (between 0-5):</p>
<h:inputText id="number" value="#{ValidatorBean.number}"
validator="#{JSFValidator.validate}"/>
<p>
<h:message style="color: orange" id="errors2" for="number"/>
</p>
<p>
<h:commandButton id="submit" action="success" value="Submit" />
</p>
</h:form>
The code above uses the built-in validator (in this case named JSFValidator) to validate the value of a provided number. If the number is not within the range, the page redisplays with an error message.
Managed Bean Method Validation
Method validation can be performed as a method defined in a managed bean or backing bean. The method bindings are mapped using the validator attribute of the UI component.
<f:view>
<h:form id="validatorForm" >
<p>
Enter a new name (other than "blueprints").
</p>
<h:inputText id="userName" value="#{ValidatorBean.userName}"
validator="#{ValidatorBean.validate}"/>
<h:commandButton id="submit" action="success" value="Submit" />
<p>
<h:message style="color: red"
id="errors1"
for="userName"/>
</h:form>
</f:view>
The JavaServer Faces page snippet above shows an input text field that uses a method called validate in a managed bean named ValidatorBean. The method to which a validator is mapped must conform to a specific method signature. The JavaServer Faces runtime provides the necessary values to this method. A developer need only provide the code to validate the input:
public void validate(FacesContext context,
UIComponent component,
Object value) throws ValidatorException {
if ((context == null) || (component == null)) {
throw new NullPointerException();
}
if (value != null) {
if (((String)value).equals("blueprints")) {
throw new ValidatorException(new FacesMessage("blueprints is invalid"));
}
}
}
The code snippet above shows the method signature of a method bound to the validator attribute of a UIComponent. The UIComponent provides the FacesContext, a reference to itself, and the value that is to be validated to the method. This method is required to throw a ValidatorException to signify that a validation error was encountered.
The image above shows what occurs when a custom validation exception occurs. In this case a validation error thrown as a ValidatorException causes the JavaServer Faces page to be redisplayed with the error message provided in the exception.
In general, it is a good practice to include validation methods in the same managed bean that defines the properties for the components referencing these methods. The reason is that the methods might need to access the component's data to determine how to handle the event or to perform the validation associated with the component.
It is good practice to use the ResourceBundle facilities of the Java[TM] 2 SDK (java.util.ResourceBundle) to keep from hard-coding error messages in Java code. This also allows you to localize the error messages. JavaServer Faces technology provides a resource bundle facility, but the developer still needs to ensure that the message format is correct.
Defining validation code as methods in a managed bean is easy for a developer with Java coding knowledge. Validators in this case would be tied to a specific UI component or managed bean. While somewhat customizable through managed bean configuration, the managed bean validators are limited.
The custom validator approach is very similar to the managed bean
approach. The method signature is the same, but in the case of the
custom validator, the method name is validate
. Developers
must do the
following:
javax.faces.validator.Validator
interface. If the state of the component is saved on the client,
this class should also implement the javax.faces.component.StateHolder
interface. <validator>
<description>
Registers the Validator implementation,
DateValidator.
</description>
<validator-id>DateValidator</validator-id>
<validator-class>com.DateValidator</validator-class>
</validator>
A JavaServer Faces page associates that validator with a UI component
implementing the
javax.faces.component.EditableValueHolder
interface. Below is an example of an <h:inputText> tag that uses
the
DateValidator
.
<h:inputText id="date1" value="11-12-99">
<f:validator validatorId="DateValidator"/>
</h:inputText>
The validator implementing the javax.faces.validator.Validator
interface is mapped to a UI component using an immediate sub
element <f:validator validatorId="DateValidator"/>
.
The validate
method on the validator class contains the validation logic as shown
below.
public void validate(FacesContext context, UI component component,
Object inputValue) {
boolean valid = false;
String value = (String)inputValue;
try {
DateFormat df = new SimpleDateFormat("mm-dd-yy");
Date d = df.parse(value);
if (d != null) valid = true;
} catch (java.text.ParseException px) {
valid = false;
} catch (java.lang.IllegalArgumentException iae) {
valid = false;
}
if (!valid) {
FacesMessage error = new FacesMessage("Date " + value +
" is invalid. Please enter a date conforming to " +
datePattern);
throw new ValidatorException(error);
}
}
Notice that the method signature is the same as the one used for a managed bean validation method.
The main drawback of using the validator class approach is that a
page author cannot configure the validation parameters on a per-UI
component basis.
Although a <c:set> tag can be used to set values on the managed
beans, this is not a
trivial task because it requires detailed knowledge of the managed
bean's mechanism and the JavaServer Faces
life-cycle model. Also, validation parameters can be hard-coded (the
date pattern "mm-dd-yy"
in
the example above) in to the validator class. In such cases, these
values could be stored in a
locale-specific java.util.ResourceBundle
class or
properties file.
While this approach is good for providing global validation for a web application, it is not as flexible when it comes to changing the validation parameters.
Custom Validators With Customizable Validation Parameters
A developer can provide customizable validation parameters to the
validator implementation class by creating a custom action that extends
javax.faces.webapp.ValidatorTag
. The parameters used
for validation can also be set using property binding expressions in
a JavaServer Faces page for each component.
A developer should do the following:
javax.faces.validator.Validator
interface. If the state of the component is saved on the client, this
class should also implement the javax.faces.component.StateHolder
interface. javax.faces.webapp.ValidatorTag
to allow the customized parameters to be provided. javax.faces.webapp.Validator
which takes the parameters set by the class extending javax.faces.webapp.ValidatorTag
and performs the validation.
The graphic above shows the artifacts needed to create a JavaServer Faces validator with customizable parameters. This validator uses a regular expression to specify date patterns.
The JavaServer Faces runtime initializes the DateValidatorTag
when
the page is processed. The DateValidatorTag
creates
an instance
of the the DateValidator
and sets the parameters based on
what was
specified in the page.The DateValidator
validate method
is shown below.
// this is called by the DateValidator tag when it is initialized
public void setDatePattern(String datePattern) {
this.datePattern = datePattern;
}
public void validate(FacesContext context, UIComponent component,
Object inputValue) {
boolean valid = false;
String value = (String)inputValue;
try {
valid = Pattern.matches(datePattern, value);
} catch(PatternSyntaxException pse) {
// something wrong with expression
}
if (!valid) {
FacesMessage error = new FacesMessage("Date " + value +
" is invalid. Please enter a date conforming to " +
datePattern);
throw new ValidatorException(error);
}
}
The code above shows the validate method of a validator for which the
datePattern was set using a custom action. This would
allow a page developer to define datePattern on a per-UI component
basis. A ValidationException
is thrown to signify an
error in the value
(inputValue
in this example) provided.
Customizable validators require some more work on the part of the
developer. A developer should develop the custom action
extending
the
javax.faces.webapp.Validator
as well as provide the
correct tag
library descriptor files. The benefit is that the validator can
be used for fine-grained validation of UI components. While validators
that use custom actions are difficult to develop, they are easy for a
page
author to use.
For more information about this topic, refer to the following: