ADF InputListOfValues Validation

Based on various sources, the InputListOfValues sometimes skips validation when the value has changed. The reasoning behind this is that the framework assumes that all values present in the LOV list are valid choices.

In reality, this may not always be the case. Especially if complex business rules dictate which values are valid; or if there is dependency for valid values between various fields. These complex validation scenarios are normally solved using a custom validator.

My solution to the issue of custom validators not being reliably called, was to subscribe to the ValueChangedEvent, and manually call each validator individually. Note that it is not enough to simply call control.validate().

JSF

  <af:inputListOfValues id="xxItNo"
                        value="#{row.bindings.ItemNo.inputValue}"
                        model="#{row.bindings.ItemNo.listOfValuesModel}"
                        autoSubmit="true"
                        valueChangeListener="#{BackingBeanInst.itemNoChangedListener}"
                        autoComplete="off">
      <f:validator binding="#{row.bindings.ItemNo.validator}"/>
      <f:validator validatorId="MultiOpItemNoValidator"/>
  </af:inputListOfValues>

Java Bean

public class BackingBeanInst {
  public void itemNoChangedListener(ValueChangeEvent valueChangeEvent) {
      log.fine("Entered itemNoChangedListener()");

      try {
            UIXInput input = (UIXInput)valueChangeEvent.getSource();
            forceInputValidation(input, valueChangeEvent.getNewValue());

            if (input.isValid()) {
                  // Perform some optional calculations if required
            } else {
                log.fine("input is invalid, skipping calculations");
            }
      } catch (Exception ex) {
            log.severe(ex);
      }
  }
}

Java Validator

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

import oracle.adf.share.logging.ADFLogger;

/**
 * Performs some arbitrary validation
 */
@FacesValidator("MultiOpItemNoValidator")
public class MultiOpItemNoValidator implements Validator {

    private static ADFLogger log = ADFLogger.createADFLogger(MultiOpItemNoValidator.class);

    @Override
    public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) throws ValidatorException {

        if (log.isFine()) {
            log.fine("in validate");
            log.fine("new value= " + value);
        }

        boolean valid = true;
        try {

            // Super Advanced Custom Validation
            valid = false;
        } catch (Exception ex) {

            log.severe(ex);
        }

        if (!valid) {

            log.info("Falied Validation: " + ve.getMessage());
    
            FacesMessage msg = new FacesMessage("Item Number Validation Failed", ve.getMessage());
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(msg);
        }
    }
}

faces-context

Remember to add your validator to faces-config.xml.