Data Validation inside a List

Posted by & filed under , , .

Felt like sharing this, since there might be some other “dinosaurs” like myself (i.e. slow in their using the Apache Commons Collections) — and those guys might find this useful 🙂

Occasionally you find yourself providing components that will be used by various modules in a project, and as such you have to employ strict validation of how the callers pass you information and reject those invalid calls — typically by throwing some exception declared in the component “contract” (interface). (I say typically as this is the preferred — read “recommended” — way of signalling these situations in Java, however, I’m not denying that there are cases when one has to instead return true / false or 1 / 0 or use some other method; in such cases, this approach can be still adapted by catching the exception at a high level and returning the corresponding value to signal failure.)

For simplicity, I will assume here we are working on an API for an Address Book component — which simply stores first name, surname and email address for a person. As such, the class you will be exposing in your API will look something like this:

public class Person {
	private String firstName;
	private String surname;
	private String emailAddress;
 
	public Person() {
		this( null, null, null );
	}
 
	public Person(String firstName, String surname, String emailAddress) {
		this.firstName = firstName;
		this.surname = surname;
		this.emailAddress = emailAddress;
	}
 
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getSurname() {
		return surname;
	}
	public void setSurname(String surname) {
		this.surname = surname;
	}
	public String getEmailAddress() {
		return emailAddress;
	}
	public void setEmailAddress(String emailAddress) {
		this.emailAddress = emailAddress;
	}
}

These entries will have to be kept in a list in memory — so somewhere inside your API you will have something like this (see below). And also in your API you have to allow somehow your callers to add new entries to the address book; now since you don’t know who’s going to use this API you need to accept the fact that sometimes you will see wrong entries being tried to added to the address book and as such you need to validate these. Let’s agree for simplicity reasons that “validation” in this case means that one cannot add null entries and also no entries with empty or null properties (firstname, surname or email!) can be added. So you will have an addPerson method that will throw an IllegalArgumentException in any of the above cases. With this in mind, your API will look like this:

public class APIInterface {
...
  private List < String > store;
...
  public void addPerson( Person p ) throws IllegalArgumentException;
}

Under the covers, your implementation for addPerson I would imagine would do something like this:

...
public void addPerson( Person p ) throws IllegalArgumentException {
  validate( p );
  //at this point, p is valid so we can use it and add it to the list
  store.add( p );
  ...
}
 
protected void validate( Person p ) throws IllegalArgumentException {
  if( p == null ) throw new IllegalArgumentException( "Cannot add null entry!" );
  if( StringUtils.isEmpty(p.getFirstName()) )
    throw new IllegalArgumentException( "Cannot add entry without a first name!" );
  if( StringUtils.isEmpty(p.getSurname()) )
    throw new IllegalArgumentException( "Cannot add entry without a surname!" );
  if( StringUtils.isEmpty(p.getEmailAddress()) )
    throw new IllegalArgumentException( "Cannot add entry without an email address!" );
}
...

This works fine, however, it doesn’t seem that “right” that the APIInterface class is responsible directly for validating this entry — and it seems a better idea to move this into a class of its own, to implement this validation. Of course this can be refactored by employing an inner class (or even anonymous inner class) but the point is your code will still have to call this validate method explicitely…

Unless of course you use the PredicatedList in Commons Collections and supply a Predicate to be used with the calls to List.add() to validate the data supplied:

public class APIInterface {
...
  private List < String > store = new PredicatedList( new ArrayList < String >(), new ValidatePersonPredicate() );
...
  public void addPerson( Person p ) throws IllegalArgumentException {
    store.add( p ); //that's it -- validation and add in one go!
    ...
  }
 
  class ValidatePersonPredicate implements Predicate {
    public boolean evaluate( Object o ) {
      if( !(o instanceof Person) ) throw new ClassCastException("not an instance of Person!" );
      Person p = (Person)o;
      if( p == null ) throw new IllegalArgumentException( "Cannot add null entry!" );
      if( StringUtils.isEmpty(p.getFirstName()) )
        throw new IllegalArgumentException( "Cannot add entry without a first name!" );
      if( StringUtils.isEmpty(p.getSurname()) )
        throw new IllegalArgumentException( "Cannot add entry without a surname!" );
      if( StringUtils.isEmpty(p.getEmailAddress()) )
        throw new IllegalArgumentException( "Cannot add entry without an email address!" );
    }
  }
}

As per usual, there’s more than one way of doing this, but this is one of the nicer ones in my opinion.