Validators

Validators (com.javelin.beans.Validator)

The purpose of Validators is to validate properties. This currently done when: -

  • Validating a Bean when a Property is set.
  • Validating a Bean prior to Creation.
  • Validating a Bean prior to Updating.
  • Validating a Bean prior to Deletion.

The validator interface has the following methods: -

public void validateOnCreate( Bean bean ) throws ValidationException;
public void validateOnStore( Bean bean ) throws ValidationException;
public void validateOnRemove( Bean bean ) throws ValidationException;

ValidatorClassWriter (com.javelin.generator.beans.ValidatorClassWriter)

The Validator Class Writer is used to write Validators.

Validators are created with the naming pattern: -

<Bean>Validator

The Validator is created in the same package as its bean. The Validator package or parent class can be modified by changing the following line in the defaultbdl.properties file: -

$VALIDATOR=public class $PACKAGE.$THIS extends $BEANS.AbstractBeanValidator

Validation Exception (com.javelin.beans.ValidationException)

The ValidationException extends the BeanException and means that there has been a problem with a property or bean.

The ValidatonException thrown by the Validators has the source and an error message set. Where the source is the property name, and the error is hardcoded a message . This means that a GUI client can set a property and catch an ValidationException and highlight the field that caused the exception with an error displaying the message.

Validate Properties

A validation method is written for every property. For example, if a car had a registration property the method has the following signature.

public void validateRegistration( String registration, Car car, String propertyName ) throws ValidationException

When properties are set on a bean the BeanClassWriter writes a call to the validator method for that property. The ValidationClassWriter writes a number of validation calls for each property, depending on the type of the property.

For example within a set method the bolded validation code is called: -

/**
* @see com.javelin.jcommerce.Address#setFirstName( java.lang.String firstName )
*/
public void setFirstName( String firstName ) throws ValidationException
{
    if( firstName != null && firstName.length() == 0 ) firstName = null;

    if( AbstractBean.isEqual( this.firstName, firstName ) ) return;

    if( isValidated() ) getValidator().validateFirstName( firstName, this, "firstName" );

    firePropertyChange( "firstName", this.firstName, this.firstName = firstName );
}

The validate properties method takes as arguments the value, the bean and the property name. The bean is passed so that the value can be checked against existing values in the bean. The property name is passed so that a ValidationException can return the name of the property that cause the exception. This property name can be used by error handlers and error display messages to highlight the error to users.

For non nullable Objects (such as String and foreign keys) the Validation code generator checks to see if the value has been set. For example: -

if( engine == null )
{
    throw new ValidationException( "Engine must have a value set.", propertyName );
}

For Strings the ValidationClassWriter checks the length of the string is less than its underlying types maximum value. For example: -

if( registration != null && registration.length() > 30 )
{
    throw new ValidationException( "The Registation is longer than the maximum length of 30.", propertyName );
}

For Enumerated Types, if a validSubset has been set the Validator checks to see if the Enumerated Type is valid (see EnumeratedTypes).

The example below shows a generated property validation method. The first line of the validateFirstName() method is created automatically, the other 2 validation checks are generated from validation rules : -

/**
* Validate the FirstName.
*/
public void validateFirstName( String firstName, Address address, String propertyName ) throws ValidationException
{
    if( firstName == null || firstName.length() == 0 )
    {
        throw new ValidationException( "FirstName must have a value set.", propertyName );
    }

    if( firstName != null && firstName.length() > 30 )
    {
        throw new ValidationException( "The FirstName is longer than the maximum length of 30.", propertyName );
    }

    if( firstName!=null && firstName.length() < 1 )
    {
        throw new ValidationException( "The firstName length is less than 1.", propertyName );
    }
}

Adding Validation Rules

One of more Validation Rules can be added to validators.

If a rule passes then the property is considered invalid and a ValidationException is thrown.

Rules are specified in the properties file with the following syntax: -

<ClassName>.<propertyName>.invalidRule.<index>=<expression>{Message}

In this syntax the '%' character is replaced by the property name. For example the following rules restrict the password property to be greater than 5 characters, not equal to the e-mail address and not equal to the word password.

Admin.password.invalidRule.0=%.length() < 6 {The % length is less than 6.}
Admin.password.invalidRule.1=%.equals( admin.getEmailAddress() ) {The % cannot be the same as the Email Address.}
Admin.password.invalidRule.2="password"Equals( % ) {The % is too obvious.}


Rules can also be added to bean - these are checked after the properties

<ClassName>.invalidRule.<index>=<expression>{Message}

Validate Create, Update, Delete

It is prudent to validate a Bean before persisting it. This is to stop dirty data being put on the store and to stop the store trying to store invalid data, then throwing an unmanaged exception that could have been caught before hand.

The three BeanValidator methods (listed above) are implemented by the ValidatorClassWriter. All three methods call a validate<Bean> method which in turn validates every property.

The difference between the 3 methods is that the validateOnCreate method checks to see if the primary key has been set. Depending on whether the method expects the primary key to be set then a ValidationException. This check to determine whether the primary key is present depends on whether the primary key is: -

  • automatic - generated by the database, therefore no PK is expected.
  • internal - generated by the create method, therefore no PK is expected.
  • external -generated by the user, therefore a PK is expected.

Stopping Validation

Bean level validation occurs when a bean is loaded from the database. To prevent this from happening use the following syntax: -

<HomeClassName>.validateOnCreate=false
<HomeClassName>.validateOnStore=false

For example: -

JdbcDirtyObject.validateOnCreate=false
JdbcDirtyObject.validateOnStore=false

Validation is not done by default when a Bean is loaded from the database. This is because it is assumed that the data is not dirty.

To reverse this behavior so that a Bean is validated when it is loaded use the following syntax: -

<HomeClassName>.validated=true

For example: -

JdbcAccountHome.validated=true
EJBAccountHome.validated=true

By default a bean is validated when every property is set. To reverse this behavior so that a bean is not validated by default, us the following syntax: -

[<ClassName>.]validated=false

For example to validate every thing except the Account bean: -

validated=false
Account.validated=true

Validation is done by default for every property. To stop validation being code generated for a property use the following syntax: -

<ClassName>.<propertyName>.validated=false

For example: -

Person.age.validated=false

Adding Validation Rules for Client Properties

Custom validators can be added for client properties in the same way they can be added for properties. The property name is key and the value is called value.

<ClassName>.clientProperty.<index>=<expression>{Message}

For example:

House.clientProperty.invalidRule.0="price".equals( key ) && value != null { The wall must be set }

House.clientProperty.invalidRule.1="price".equals( key ) && new Integer(value).intValue() > 0 { The wall must be > 0 }