ignore

Adding Validators

To add validators you make use of the Annotation Factory pattern, a technique used throughout Strecks. This enables you to add validators and other customizations without changing any existing configuration or Java files. There are three steps required to add a new validator.

  1. Write your validator, which needs to implement the interface Validator. The interface defines a single method:

    public boolean validate(T value);
    

    where T is a Java 5 generic type extending Object. In other words, validation is supported not only on Strings but any object. Bear in mind that, Strecks supports two types of validators: validators which use the raw or existing value of an ActionForm property, and validators which use a converted value.

    The validation interface definition also allows for Validators which can be shared with the business tier.

    Our implementation of IntegerRangeValidator is very straightforward, because it does not need to do any type conversion:
    public class IntegerRangeValidator extends IntegerValidator 
        implements Validator<Integer>
    {
    
        private int min = Integer.MIN_VALUE;
    
        private int max = Integer.MAX_VALUE;
    
        public IntegerRangeValidator()
        {
            super();
        }
    
        public boolean validate(Integer value)
        {
            boolean ok = super.validate(value);
            if (!ok)
                return false;
            return GenericValidator.isInRange(value.intValue(), min, max);
        }
        
        //getters and setters omitted
        
    }
    
  2. Create an annotation for the validator. The purpose of the annotation is to configure the validator, so any configuration parameters will need to be specified in the annotation definition. For example @ValidateIntegerRange annotation has the following form:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @ValidatorFactoryClass(ValidateIntegerRangeFactory.class)
    public @interface ValidateIntegerRange
    {
        String key();
    
        int order() default 999;
    
        int min() default Integer.MIN_VALUE;
    
        int max() default Integer.MAX_VALUE;
    }
    

    An example usage is shown below, with the key being the String used to look up validation error messages from the MessageResources database:

    @ValidateIntegerRange(key = "not.in.range", min = 0, max = 1)
    public void setIntegerRangeValue(String integerRangeValue)
    {
        this.integerRangeValue = integerRangeValue;
    }
    
  3. Notice the @ValidateIntegerRange definition uses the @ValidatorFactoryClass annotation. This annotation determines which factory class, or ValidatorFactory implementation, is needed to create the Validator instance from the annotation.

    Our implementation for ValidateIntegerRangeFactory is shown below:

    public class ValidateIntegerRangeFactory extends BaseFactory
    {
    
        public ValidatorWrapper create(Annotation annot, Method method)
        {
            ValidateIntegerRange annotation = (ValidateIntegerRange) annot;
            IntegerRangeValidator validator = new IntegerRangeValidator();
    
            validator.setMin(annotation.min());
            validator.setMax(annotation.max());
    
            List<Object> parameters = new ArrayList<Object>();
            parameters.add(annotation.min());
            parameters.add(annotation.max());
    
            return createWrapper(validator, 
              annotation.key(), annotation.order(), parameters, method);
        }
    
    }
    

    As well as instantiating the Validator, the ValidatorFactory creates a ValidatorWrapper with additional information required at runtime for validation. Most of the latter task is performed by the BaseFactory implementation.

Configuring Message Parameters

The convention is that for any new validator to use a String key for looking up the appropriate validation message from a message resource bundle. When creating these messages, it is common to parameterize these with values. For example, a message could be:

days.outside.range=The number of days specified 
	{0} is outside the range of {1} to {2}

By default, the first value available for parameterizing the message is the inputted value. Any other values available depend on what parameters have been added in the ValidatorFactory implementation. In our ValidateIntegerRangeFactory implementation above, the annotation's min and max attributes have been added.

If you want to depart from this scheme in your own implementation, you can override BaseFactory's newMessageParameterProvider() method, and provide an alternative MessageParameterProvider implementation. This could be useful, for example, in validating a FormFile object in a file upload. Here, the MessageParameterProvider may need to separately expose parts of the uploaded FormFile as individual message parameters.

SourceForge.net logo java.net Member logo Copyright © 2005-2007 Realsolve Solutions