Archive

Posts Tagged ‘Object Validation’

OVal -Object Validation With POJO

April 14, 2009 1 comment

From the Oval site:

OVal is a pragmatic and extensible validation framework for any kind of Java objects (not only JavaBeans).

Constraints can be declared with annotations (@NotNull, @MaxLength), POJOs or XML.

Custom constraints can be expressed as custom Java classes or by using scripting languages such as JavaScript, Groovy, BeanShell, OGNL or MVEL.

Oval has 3 ways to do object validation : inline Annotations, XML files and POJO validation. They actually talk about the POJO Validation in their main page, but when you go looking for more information on this it’s nowhere to be found. I managed to find some old test cases with some info that helped me get this going.

Let me be honest, POJO validation is probably the worst thing you can do. Avoid doing something like this at all costs. Its ugly and high maintenance. Go for Annotations if you can, or XML if you don’t want the added dependency. Since the calls are done by reflection you will not get compile time errors when you change objects, i actually ran into this problem a week after implementing the validator. Note that this will also happen with XML validation, which is also high maintenance (and ugly, but this one is worse).

So lets get our hands dirty then…

Take the following objects as an example (the objects have getter and setter methods for every property):

public class Person{
    private String name;
    private int age;
    private Clothing[] clothes;
    private Car car;
}

public class Car{
    private String brand;
}

public class Clothing{
    private String size;
}

Take the following Rules for validation:

  1. a person must have a name;
  2. a persons age must be higher than 0;
  3. a person must have at least one piece of clothes
  4. a person may not have a car
  5. a car must have a brand
  6. size in clothes must match one of the following : “S”,”M”,”L”;

To start your POJO Validator off you need to create a PojoConfigurer instance and a ClassConfiguration Set.

POJOConfigurer  mainConfiguration  = new POJOConfigurer();
Set<ClassConfiguration> classConfigs = new HashSet<ClassConfiguration>();
//make sure to tell your mainConfiguration Object to use the Set you have created:
mainConfiguration.setClassConfigurations(classConfigs);
//You must also create an Oval validator based on your POJOConfigurer
net.sf.oval.Validator validator = new net.sf.oval.Validator(mainConfiguration);

All this is pretty simple and straightforward. now comes the ugly part, the rules:

To define the validation rules you need to create checks for every property(or method) and add it to your class configs.

First we will create the validations for the Person class by creating a ClassConfiguration and adding it to our Set

final ClassConfiguration personConfig = new ClassConfiguration();
classConfigs.add(personConfig);
personConfig.type = Person.class;
personConfig.methodConfigurations = new HashSet<MethodConfiguration>();

The code above also initializes the methodConfiguration set for this class. now for each property we will define the validations to perform. Note that the validation is done on the getter method for each property:

1. a person must have a name;

final MethodConfiguration mc = new MethodConfiguration();
personConfig.methodConfigurations.add(mc);
mc.name = "getName";
mc.isInvariant =  Boolean.TRUE;
mc.returnValueConfiguration = new MethodReturnValueConfiguration();
mc.returnValueConfiguration.checks = new ArrayList<Check>();
final NotNullCheck vM = new NotNullCheck();
vM.setMessage("Name is mandatory.");
mc.returnValueConfiguration.checks.add(vM);

This is straightforward, we simply add a NotNullCheck to make sure this object is not null.

2. a persons age must be higher than 0

final MethodConfiguration mc = new MethodConfiguration();
cf.methodConfigurations.add(mc);
mc.name = "getAge";
mc.isInvariant =  Boolean.TRUE;
mc.returnValueConfiguration = new MethodReturnValueConfiguration();
mc.returnValueConfiguration.checks = new ArrayList<Check>();
final MinCheck vM2 = new MinCheck();
vM2.setMin(1);
vM2.setMessage("Age must be higher than 0.");
mc.returnValueConfiguration.checks.add(vM2);

This one is also very simple we added a check to validate that the age is higher than 0(RangeCheck and MaxCheck also available).

3. a person must have at least one piece of clothes

final MethodConfiguration mc = new MethodConfiguration();
cf.methodConfigurations.add(mc);
mc.name = "getClothes";
mc.isInvariant =  Boolean.TRUE;
mc.returnValueConfiguration = new MethodReturnValueConfiguration();
mc.returnValueConfiguration.checks = new ArrayList<Check>();
final SizeCheck vM2 = new SizeCheck();
vM2.setMin(1);
vM2.setMessage("Person must cannot be naked.");
mc.returnValueConfiguration.checks.add(vM2);
final AssertValidCheck assValid = new AssertValidCheck();
mc.returnValueConfiguration.checks.add(assValid);

Here we add a SizeCheck to make sure our array has at least one Note that in this case we added a second Check. AssertValidCheck is telling Oval that he must also validate that object using its own class configuration.

4. a person may not have a car

final MethodConfiguration mc = new MethodConfiguration();
cf.methodConfigurations.add(mc);
mc.name = "getClothes";
mc.isInvariant =  Boolean.TRUE;
mc.returnValueConfiguration = new MethodReturnValueConfiguration();
mc.returnValueConfiguration.checks = new ArrayList<Check>();
final AssertValidCheck assValid = new AssertValidCheck();
mc.returnValueConfiguration.checks.add(assValid);

This rule only requires that we tell Oval to validate the object to make sure it is also valid

5. a car must have a brand

This is a simple NotNullCheck, make sure to create a new ClassConfiguration as shown above.

6. size in clothes must match one of the following : “S”,”M”,”L”;

We need to create a new ClassConfiguration for this Object then we must add the following check

final MethodConfiguration mc = new MethodConfiguration();
cf.methodConfigurations.add(mc);
mc.name = "getSize";
mc.isInvariant =  Boolean.TRUE;
mc.returnValueConfiguration = new MethodReturnValueConfiguration();
mc.returnValueConfiguration.checks = new ArrayList<Check>();
MemberOfCheck mbCheck= new MemberOfCheck();
mbCheck.setMembers("S","M","L");
mc.returnValueConfiguration.checks.add(mbCheck);

The above rules are all simple enough that you will not need to make your own validation. Though you might find your self needing to define a method to validate a given property. Oval also has an option for this, with a slight anti-feature. You can easily right a method and tell Oval to validate your property using that method by using the ValidateWithMethodCheck. Only problem with this Check is that it requires that the validating method be inside the Original object. You can allways override this class and make it call your own object, like so:

public class ValidateWithObjectValidator  extends ValidateWithMethodCheck{
    @Override
    public boolean isSatisfied(Object validatedObject, Object valueToValidate, OValContext context, Validator validator)
            throws ReflectionException {
        //Ignore the validatedObject use ValidatorUtil Instead

        return super.isSatisfied(new ValidatorUtil(), valueToValidate, context, validator);
    }
}

ValidatorUtil is the Object that contains my validation methods. You can use this Check in the same way you would use ValidateWithMethodCheck:

final ValidateWithObjectValidator vM = new ValidateWithObjectValidator();
vM.setParameterType(String.class);
vM.setMethodName("validateDate");
vM.setIgnoreIfNull( true);
vM.setErrorCode("2");
vM.setMessage("Data de Estabelecimento do Operador Inválida.");

Hope this helps somebody out there.

Reference Links :