Bean Validation and transformation

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.

Getting ready

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>

How to do it…

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>

How it works…

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.

There's more…

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}"/>

See also

  • PrimeFaces provides messages in the beanvalidation.js file that can be customized, as described in the Configuring and getting started with CSV recipe
  • The Extending CSV with Bean Validation recipe shows you how to write custom validators for Bean Validation and how to add new messages

PrimeFaces Cookbook Showcase application

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.52.188