Skip to content

Tutorial 4. Advanced Validation

Osman Shoukry edited this page May 22, 2016 · 7 revisions

The Problem

It is rarely the case that all you want to do is just validate getters and setters.

Have you ever
  • Missed a serialVersionUID on a serializable?
  • Declared something as int then resorted to -1 to indicate it was not set?
    • Or regretted using a primitive boolean because you needed three states later on (unset, true and false)?
  • Declared a field static and modified it accidentally causing all sorts of issues?
  • Accidentally shadowed a field declared in a parent class?

If any of this rings a bell, you aren't alone, I have done it too, and that is why you'll want your Validator to get smarter about what it looks for, a LOT smarter.

Possible Solution

To make our Validator smarter, we'll load it up with rules, we want to be careful around what we load it up with and the compatibility of some of those rules, here is a good list to start with:

public class PojoTest {
  // Configured for expectation, so we know when a class gets added or removed.
  private static final int EXPECTED_CLASS_COUNT = 1;

  // The package to test
  private static final String POJO_PACKAGE = "com.openpojo.samplepojo";

  private List<PojoClass> pojoClasses;
  private Validator validator;

  @Before
  public void setup() {
    pojoClasses = PojoClassFactory.getPojoClasses(POJO_PACKAGE, null);
    validator = ValidatorBuilder.create()
        /****
         * Create Rules to validate structure of the classes
         ****/
        // Make sure we have a getter and setter
        .with(new GetterMustExistRule())
        .with(new SetterMustExistRule())

        // We don't want any primitives in our Pojos.
        .with(new NoPrimitivesRule())

        // Pojo's should stay simple, don't allow nested classes, anonymous or declared.
        .with(new NoNestedClassRule())

        // Static fields must be final
        .with(new NoStaticExceptFinalRule())

        // Serializable must have serialVersionUID
        .with(new SerializableMustHaveSerialVersionUIDRule())

        // Don't shadow parent's field names.
        .with(new NoFieldShadowingRule())

        // What about public fields, use one of the following rules
        // allow them only if they are static and final.
        .with(new NoPublicFieldsExceptStaticFinalRule())

        // Or you can be more restrictive and not allow ANY public fields in a Pojo.
        // pojoValidator.addRule(new NoPublicFieldsRule());

        // Finally, what if you are testing your Testing code?
        // Make sure your tests are properly named
        .with(new TestClassMustBeProperlyNamedRule())

        /****
         * Create Testers to validate the behavior of the classes at runtime.
         ****/
        // Make sure our setters and getters are behaving as expected.
        .with(new SetterTester())
        .with(new GetterTester())

        // We don't want any default values to any fields - unless they are declared final or are primitive.
        .with(new DefaultValuesNullTester())

        /**
         * finalize Validator building.
         */
        .build();
  }

  @Test
  public void ensureExpectedPojoCount() {
    Assert.assertEquals("Classes added / removed?", EXPECTED_CLASS_COUNT, pojoClasses.size());
  }

  @Test
  public void testPojoStructureAndBehavior() {
    validator.validate(pojoClasses);
  }
}