Please help with validation

Vaadin 7 is really a great redesign, congratulations to the Vaadin team! It is so better redesigned that I decide once more to postpone a project after migration to Vaadin 7, but I’m facing difficulties with the new validation framework.

Bean validation apart (I will stay with Vaadin plain validators), what is not clear to me is what client code shall exactly do, to avoid flagging not initialized fields with errors. Looking at the example with bean validators I see lot of repeated code to attach and detach validators form each field. Honestly that seems to me an overkill and error prone strategy.

What I am considering to do is a reusable method that walks down the component tree stripping all validators from the fields and collecting them into a map, and attaches to each field a blur listener that will reattach all validators to the field (removing them from the map) and finally remove itself (the blur listener) from the field.

Before committing the form a second method will be called that collects what still in the map and attaches to fields that never lost focus.

This is what I figured, but still seems to me a little tricky.

Is there a better alternative? Am I missing something?

The code. Works but I’m still asking: is this the right way?


import com.vaadin.data.Validator;
import com.vaadin.event.FieldEvents;
import com.vaadin.ui.AbstractComponentContainer;
import com.vaadin.ui.Component;
import com.vaadin.ui.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * This class can be used to avoid initialized fields marked as invalid.
 * Validation is delayed until each field lose focus or restore() is
 * called to restore all validators, for example before post.<br/>
 * To use this class create a ValidatorDelayer passing the form container
 * <b>after all fields have been added</b>. Call restore() before post.
 */
public class ValidatorDelayer implements FieldEvents.BlurListener {

  private Map<Field, List<Validator>> parked = 
          new HashMap<Field, List<Validator>>();
  
  
  public ValidatorDelayer(Component container) {
    captureValidators(container);
  }
          
  private void captureValidators(Component component) {
    if (component instanceof Field)
      parkValidators((Field) component);
    if (component instanceof AbstractComponentContainer) {
      Iterator<Component> iter = ((AbstractComponentContainer) component).iterator();
      while (iter.hasNext())
        captureValidators(iter.next());
    }
  }

  private void parkValidators(Field field) {
    Iterator<Validator> iter = field.getValidators().iterator();
    List<Validator> l = new ArrayList<Validator>();
    l.addAll(field.getValidators());
    field.removeAllValidators();
    if (l.isEmpty())
      return;
    parked.put(field, l);
    if (field instanceof FieldEvents.BlurNotifier) {
      ((FieldEvents.BlurNotifier) field).addBlurListener(this);
    }
  }

  @Override
  public void blur(FieldEvents.BlurEvent event) {
    Field field = ((Field)event.getSource());
    if (restoreValidators(field))
      parked.remove(field);
  }
  
  private boolean restoreValidators(Field field) {
    List<Validator> l = parked.get(field);
    if (l != null) {
      System.out.println("restoring validators for " + field.getCaption());
      for (Validator validator: l) {
        System.out.println("    " + validator.getClass());
        field.addValidator(validator);
      }
      if (field instanceof FieldEvents.BlurNotifier)
        ((FieldEvents.BlurNotifier) field).removeBlurListener(this);
      return true;
    }
    return false;
  }
  
  public void restore() {
    for (Field field: parked.keySet())
      restoreValidators(field);
    parked.clear();
  }
  
}