Validating input received from the user to maintain data integrity is an important part of application logic. Validation of data can take place at different layers in an application. Bean Validation (http://beanvalidation.org) is a validation model available as part of the Java EE 6 platform, which allows validation by constraints in the form of annotations placed on a field, method, or class. JSF 2.2 supports validation placed on fields (properties and their getters/setters) in managed beans as well as Spring and CDI beans. Validation on the class level is not supported as long as you do not use utilities such as OmniFaces (http://showcase.omnifaces.org/validators/validateBean).
The PrimeFaces' CSV has a built-in integration with Bean Validation. Constraints defined with annotations can be validated on the client side by the CSV Framework.
In this recipe, we will develop an example with all available standard Bean Validation constraints. These constraints correspond to the @AssertFalse
, @AssertTrue
, @DecimalMax
, @DecimalMin
, @Digits
, @Future
, @Past
, @Max
, @Min
, @NotNull
, @Null
, @Pattern
, and @Size
annotations. PrimeFaces provides client-side validators for all mentioned annotations.
To enable Bean Validation, a Maven artifact for the Validation API is required. The following dependency in pom.xml
ensures that we can use Bean Validation Framework:
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> <scope>provided</scope> </dependency>
We put all constraint annotations in the BVBean
bean on its properties, as shown in the following code:
@Named(value = "bvBean") @ViewScoped public class BVBean implements Serializable { @AssertFalse private boolean supported; @AssertTrue private boolean active; @DecimalMin("5.00") @DecimalMax("30.00") private BigDecimal discount; @Digits(integer = 6, fraction = 2) private Double price; @Future private Date eventDate; @Past private Date birthday; @Min(5) @Max(10) private int quantity; @NotNull private String username; @Null private String unusedString; @Pattern(regexp = "\(\d{3}\)\d{3}-\d{4}") private String phoneNumber; @Size(min = 2, max = 50) private String briefMessage; // getters / setters ... }
In Facelets, the properties are bound to the values of p:selectBooleanCheckbox
and p:inputText
. This is shown in the following code:
<p:messages id="messages"/> <h:panelGrid id="grid" columns="2" cellpadding="3" style="margin-bottom:10px;"> <p:outputLabel for="input1" value="Boolean @AssertFalse"/> <p:selectBooleanCheckbox id="input1" value="#{bvBean.supported}"/> <p:outputLabel for="input2" value="Boolean @AssertTrue"/> <p:selectBooleanCheckbox id="input2" value="#{bvBean.active}"/> <p:outputLabel for="input3" value="BigDecimal @DecimalMin / Max"/> <p:inputText id="input3" value="#{bvBean.discount}"/> <p:outputLabel for="input4" value="Double @Digits"/> <p:inputText id="input4" value="#{bvBean.price}"/> <p:outputLabel for="input5" value="Date @Future"/> <p:inputText id="input5" value="#{bvBean.eventDate}"> <f:convertDateTime pattern="MM/dd/yyyy"/> </p:inputText> <p:outputLabel for="input7" value="Date @Past"/> <p:inputText id="input7" value="#{bvBean.birthday}"> <f:convertDateTime pattern="MM/dd/yyyy"/> </p:inputText> <p:outputLabel for="input8" value="int @Min / @Max"/> <p:inputText id="input8" value="#{bvBean.quantity}"/> <p:outputLabel for="input9" value="String @NotNull"/> <p:inputText id="input9" value="#{bvBean.username}"/> <p:outputLabel for="input10" value="String @Null"/> <p:inputText id="input10" value="#{bvBean.unusedString}"/> <p:outputLabel for="input11" value="String @Pattern"/> <p:inputText id="input11" value="#{bvBean.phoneNumber}"/> <p:outputLabel for="input12" value="String @Size"/> <p:inputText id="input12" value="#{bvBean.briefMessage}"/> </h:panelGrid> <p:commandButton validateClient="true" value="Submit" ajax="false" onclick="PF('inputValuesWdgt').hide()"/>
If validation fails, errors are shown in p:messages
. Otherwise, valid input values are shown in p:dialog
on postback. The following code shows this:
<p:dialog header="Input values" closeOnEscape="true" visible="#{facesContext.postback and !facesContext.validationFailed}" widgetVar="inputValuesWdgt"> <h:panelGrid id="inputValues" columns="1" cellpadding="3"> <h:outputText value="#{bvBean.supported}"/> <h:outputText value="#{bvBean.active}"/> <h:outputText value="#{bvBean.discount}"/> <h:outputText value="#{bvBean.price}"/> <h:outputText value="#{bvBean.eventDate}"> <f:convertDateTime pattern="MM/dd/yyyy"/> </h:outputText> <h:outputText value="#{bvBean.birthday}"> <f:convertDateTime pattern="MM/dd/yyyy"/> </h:outputText> <h:outputText value="#{bvBean.quantity}"/> <h:outputText value="#{bvBean.username}"/> <h:outputText value="#{bvBean.unusedString}"/> <h:outputText value="#{bvBean.phoneNumber}"/> <h:outputText value="#{bvBean.briefMessage}"/> </h:panelGrid> </p:dialog>
In the example, the input components are validated on the client side by setting validateClient="true"
on p:commandButton
. Thanks to PrimeFaces' built-in client-side validators and converters, we do not need to deal with writing any JavaScript code. However, there is one specialty of the @NotNull
constraint—that input is required. By default, JSF treats no input as an empty string. In this case, an empty string will pass this validation constraint. However, if you set the javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
context parameter in web.xml
to true
, the value of the bean property is passed to the Bean Validation runtime as a null
value, causing the @NotNull
constraint to fail.
PrimeFaces can take certain Bean Validation constraints and transform them into component and HTML attributes. These transformations avoid manual maintenance of these attributes for component tags. For instance, the required
and maxlength
attributes are not required to be set when the @NotNull
and @Size
annotations are available. Transformation is enabled by setting the following context parameter in web.xml
:
<context-param> <param-name>primefaces.TRANSFORM_METADATA</param-name> <param-value>true</param-value> </context-param>
Now, you can write the following in a bean:
@NotNull @Max(140) private String sms;
You can omit the required
and maxlength
attributes for p:inputText
because the HTML output gets maxlength="140"
from the @Max(140)
annotation, and the component's required
attribute is set to true
due to the @NotNull
annotation:
<p:inputText value="#{bean.sms}"/>
This recipe is available in the demo web application on GitHub (https://github.com/ova2/primefaces-cookbook/tree/second-edition). Clone the project if you have not done it yet, explore the project structure, and build and deploy the WAR file on application servers compatible with Servlet 3.x, such as JBoss WildFly and Apache TomEE.
The showcase for the recipe is available at http://localhost:8080/pf-cookbook/views/chapter10/bvCsv.jsf
.