Friday, December 25, 2009

Integrating JSR 303 Bean Validation with Oracle ADF 11g

In this post, I will try to show you how we were able to successfully integrate the JSR 303 Bean Validation into our ADF 11g Application built with EJB/JPA. The result is a centralized area to define validation constraints using annotations which can be invoked from any layer of the application.

Below is the screen-shot of a sample edit page created with the JSR 303 Bean Validation:
To apply JSR 303 Bean Validation a project, we need to do the following steps:
  1. Download the JSR 303 reference implementation from Hibernate.
  2. Add the 5 jar files into your Model project's Libraries and Classpath (Project Properties).
  3. Annotate your entities with validation annotations like the sample code snippet below:
    import javax.validation.constraints.DecimalMax;
    import javax.validation.constraints.Max;
    import javax.validation.constraints.Size;
    public class Employee implements Serializable {
        @Column(name="EMPLOYEE_ID", nullable = false)
        private Long employeeId;
        @Column(name="FIRST_NAME", length = 20)
        @Size(min = 3, max = 20)
        private String firstName;
        @Column(name="LAST_NAME", nullable = false, length = 25)
        @Size(min = 3, max = 20)
        private String lastName;
        private Double salary;
        private Double commissionPct;
  4. Create a utility class that will handle extraction of validation messages like the one below:
    package com.blogspot.soadev.util;
    import java.util.Set;
    import javax.validation.ConstraintViolation;
    import javax.validation.Validation;
    import javax.validation.ValidatorFactory;
    public class MyUtils {
        public static javax.validation.Validator getValidator() {
            ValidatorFactory factory =
            return factory.getValidator();
        public static String extractConstraintViolationMessages(Set violations) {
            StringBuilder builder = new StringBuilder();
            for (Object obj : violations) {
                if (obj instanceof ConstraintViolation) {
            return builder.toString();
        //This method returns a set of validation constraint errors
        public static Set validateEntity(Object object) {
            javax.validation.Validator validator = getValidator();
            return validator.validate(object);
        // returns null if no violation
        public static String getEntityValidationErrorMsg(Object object) {
            Set violations = validateEntity(object);
            if (violations.size() > 0) {
                return extractConstraintViolationMessages(violations);
            return null;
  5. In the ViewController project, create the following class that implements javax.faces.validator.Validator.
    package com.blogspot.soadev.view.validator;
    import com.blogspot.soadev.util.MyUtils;
    import com.blogspot.soadev.view.util.JSFUtils;
    import java.util.Set;
    import javax.el.ELException;
    import javax.faces.FacesException;
    import javax.faces.application.FacesMessage;
    import javax.faces.component.EditableValueHolder;
    import javax.faces.component.UIComponent;
    import javax.faces.context.FacesContext;
    import javax.faces.validator.Validator;
    import javax.faces.validator.ValidatorException;
    import javax.validation.ConstraintViolation;
    import javax.validation.Validation;
    public class BeanValidator implements Validator {
        private static final String DOT_REGEX = "[.]";
        private static final String BINDINGS = "bindings";
        private static final String INPUT_VALUE = "inputValue";
        private static final String NAME = "name";
        private static final String EMPTY_STRING = "";
        private static final String END_CURLY_BRACKET = "}";
        private static final String DATA_PROVIDER = "currentRow.dataProvider";
        private static final String DOT = ".";
        public BeanValidator() {
        public void validate(FacesContext facesContext, UIComponent component,
                             Object object) throws ValidatorException {
            if (component instanceof EditableValueHolder) {
                // Validate input component
                EditableValueHolder input = (EditableValueHolder)component;
                try {
                    String expression =
                    if (null != expression) {
                        Set<ConstraintViolation<Object>> constraintViolations =
                            validateValue(object, expression);
                        if (constraintViolations.size() > 0) {
                            // send all validation messages.
                            String msg =
                            FacesMessage fm =
                                new FacesMessage(FacesMessage.SEVERITY_ERROR, msg,
                            throw new ValidatorException(fm);
                } catch (ELException e) {
                    throw new FacesException(e);
        private Set<ConstraintViolation<Object>> validateValue(Object object,
                                                                                 String expression) {
            Object targetObject = getTargetObject(expression);
            String property = getProperty(expression);
            javax.validation.Validator validator =
            Set constraintViolations =
                validator.validateValue(targetObject.getClass(), property, object);
            return constraintViolations;
        public String getProperty(String expression){
            if (expression.contains(BINDINGS) && expression.contains(INPUT_VALUE)){
               expression =
                    expression.replaceFirst(INPUT_VALUE, NAME);       
                return JSFUtils.resolveExpression(expression).toString();
            String [] tokens = expression.split(DOT_REGEX);
            String result  = tokens[tokens.length-1];
            result = result.replaceAll(END_CURLY_BRACKET, EMPTY_STRING);
            return result;
        public Object getTargetObject(String expression){
            if (expression.contains(BINDINGS) && expression.contains(INPUT_VALUE)){
                expression =
                    expression.replaceFirst(INPUT_VALUE, DATA_PROVIDER);
                return JSFUtils.resolveExpression(expression);
                String [] tokens = expression.split(DOT_REGEX);
                StringBuilder builder = new StringBuilder(tokens[0]);
                for (int i = 1; i < tokens.length - 1; i++){
                return JSFUtils.resolveExpression(builder.toString());        
  6. Add the JSR303BeanValidator class above to the list of validators in faces-config.xml
  7. Apply the JSR303BeanValidator to your input components in ADF Faces.
    <af:inputText value="#{bindings.firstName.inputValue}"
                                        id="it2" autoSubmit="true">
                            <f:validator validatorId="JSR303BeanValidator"/>
                          <af:inputText value="#{bindings.lastName.inputValue}"
                                        id="it4" autoSubmit="true">
                            <f:validator validatorId="JSR303BeanValidator"/>
                          <af:inputText value="#{bindings.salary.inputValue}"
                                        id="it3" autoSubmit="true">
                            <f:validator validatorId="JSR303BeanValidator"/>
                            <af:convertNumber groupingUsed="false"
  8. Run your project and try to input invalid values. To display the validation error messages after you tab out of a component, ensure to set the "AutoSubmit" attribute of the component to true.

To know more about JSR 303, click here and here.

Related Posts

No comments:

Post a Comment