Sunday, June 8, 2014

Using Bean Validation in Oracle ADF

Oracle ADF version 12c runs on Java EE 6 container Weblogic 12c.  ADF Faces 12c (current version 12.1.2) is based on Java Server Faces 2.1 standard.

Version 2 of JSF introduced support for Bean Validation , as described in  JSF specification ( Chapter 2.5.7). To summarize: it basically states,  that java bean properties , annotated with Bean Validation constraints, are going to be validated automatically by the underlying JSF implementation.

ADF as Java EE (and therefore JSF) standards based framework provides an extended functionality with a special focus on productivity and declarative development. An example of such functionality is ADF Binding Layer, which helps to access a data from user interface a unified way.

The blog post provides a sample implementation of ADF BeanValidator to close a small integration gap between a functionality specified by JSF and ADF (specifically ADF binding layer).

Note: the usage of Bean Validation might provide most benefits in case your ADF usage scenario includes an alternative to ADF Business Components, like EJBs or Webservices   In case of ADF "full-stack" usage there might be no benefits in using Bean Validation comparing it to integrated validation functionality available in ADF.

Lets have a look at the structure of the sample application, available to download and run in JDeveloper 12c (12.1.2).

Using ADF Bean Validator


The are two Projects in a Workspace: ADFBeanValidationSample and ADFBeanValidationValidator:


The first project ADFBeanValidationSample  is a simple ADF Application supposed to be used in a business area "Human Resources" at some company. I will describe a structure of it  and the steps used to create it very briefly.

The model consists of one java bean  Employee.java with 2 properties: id and name.


The properties are annotated with JSR 303 Bean Validation constrains: @NotNull and @Size. The constrains supposed to make sure, that values for both properties are provided and size of a name fits into a boundaries defined.

There is one "service" , named HRService.java, which exposes a list of Employees as ADF Bean Data Control:

Two JSF pages (list.jsf and form.jsf) with bindings to HRService.employeeList were created in JDeveloper usual declarative way (Drag&Drop .

We start the sample -- a page list.jsf with a list of  employees shows up:

It looks like we are dealing with some early-stage startup  with two employees :) Lets hire a new one.

We click on a link Create - a new row gets inserted into the table. We enter a data of our new hire and click on Submit:


JSR303 Bean Validation constraint @Size(min = 3,max=20) on a property name in a bean Employee.java kicks in.

Unfortunately we can't submit the data of our new hire at a moment. We "tune" our business rules and fix our business model Employee.java this way: @Size(min = 2,max=20).

Mr. Wu is able to join our company as a result of our efforts.

Lets look at the second project ADFBeanValidationValidator for the implementation details.

ADF Bean Validator implementation details

 

Note:  early ADF and Bean Validation  integration is also described in a blog post of Romel Pino

The second project ADFBeanValidationValidator (configured as a dependency) , provides ADFBeanValidator.java  to close a gap between JSF and ADF binding layer.


ADFBeanValidator class (extends standard BeanValidator) is annotated with @FacesValidator and configured as a default:

...
@FacesValidator(value = "com.nicequestion.donatas.adf.validate.ADFBeanValidator",isDefault = true)
public class ADFBeanValidator extends BeanValidator {
...

Therefore it gets attached to every UIInput element and gets executed on a validate phase of JSF lifecycle automatically without additional configuration and development efforts.

The implementation does basically the following:

  • Backups ADF bindings value expression
  • Rewrites (temporary) ADF bindings value expression of UIComponent to resolve to a bean property value, e.g: 
    • for iterator row binding expression:  
      • from #{row.bindings.name.inputValue} 
      • to {row.bindings.name.currentRow.dataProvider.name}
    • for attribute binding:
      • from #{bindings.name.inputValue}
      • to  #{bindings.name.currentRow.dataProvider.name}
  • Delegates to standard BeanValidator - validates a property.
  • Restores an original ADF value expression from a backup.

ADF binding expressions don't work because they resolve to a Map interface. And a Map is not validated by a standard JSF BeanValidator.

In order to compensate that we can get a functionality of Bean Validation in ADF Project simply by including our ADFBeanValidator as a dependency.

Take a look at the source for additional implementation details - and fell free to use and adapt it for you needs in case of interest:

A complete source is also provided at Github.