Skip to content
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.

Entity validation

Alex edited this page Dec 17, 2015 · 3 revisions

The release 0.1.3 of droitatedDB contains entity validation. With this feature it is possible to annotate your @Columns within @Entities with a validator. The validators on columns will be executed when trying to save a @Entity to the database using the EntityService. In case you don't want to use this feature you can opt-out with the corresponding constructor argument of the EntityService.

It is also possible to execute the validators within an @Entity, without saving it to the database. Just create an instance of DatabaseValidator and call validate.

Using validators

You can use the build in validators by annotating your columns within your @Entity. To see what validators a available out of the box the the package org.droitatedDB.validation in the JavaDoc.

As an example a simple @Entity is created and the column foo will be annotated with @Min, @Max and @NotNull. This validators will check if the value of the column is greater or equal to 4 (@Min(5)), the column is less or equal to 25 (@Max(25)) and make sure the value is not null as well.

Be aware that the validators will only be executed on fields annotated with @Column and are within an @Entity.

@Entity
public class ValidatingEntity {
    @Column
    @PrimaryKey
    private Integer _id;

    @Column
    @NotNull
    @Min(4)
    @Max(25)
    private Integer foo;

    public void setFoo(int foo) {
        this.foo = foo;
    }
}

Using the EntityServices save method an @Entity with validators will be validated before storing it in the database. In case your @Entity has relationships to other @Entites they will be validated as well. This means before storing your @Entity the whole object graph will be validated.

ValidatingEntity entity = new ValidatingEntity();
EntityService service = new EntityService<ValidatingEntity>(this, ValidatingEntity.class);
try{
   service.save(entity);
} catch(InvalidEntityException e){
  List<ValidationResult> erros = e.getErrors();
  // process errors
}

If you don't want to store your @Entity but still validate it use the DatabaseValidator class.

DatabaseValidator validator = new DatabaseValidator<ValidatingEntity>(this);
AccumulatedValidationResult result = validator.validate(entity);

if(result.isValid()){
   // continue if valid
}

The given max depth is considered when validating the @Entity. Therefore the object graph is only validated until the maximum depth is reached.

Creating validators

Instead of only using the build-in validators you can create your own validators as well. A custom validator consists of two parts:

  1. The validator annotation
  2. The implementation of the validator

First of all create an annotation that is marked with the @Validator annotation itself. The @Validator annotation take one parameter. It is the reference to the class implementing the validation rules. Besides the @Validator annotation the validator has to be marked with @Retention(RetentionPolicy.RUNTIME) and with @Target(ElementType.FIELD). You can specify parameters as well, but be aware the are only Numbers and Strings are allowed at this moment.

Allowed parameter values:

  • int / java.lang.Interger
  • long / java.lang.Long
  • double / java.lang.Double
  • float / java.lang.float
  • byte / java.lang.byte
  • short / java.lang.Short
  • java.lang.String
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Validator(LengthValidator.class)
public @interface Length {
    long min() default -1;

    long max() default -1;
}

The class executing the validation rule, in this case LengthValidator, has to implement org.droitatedDB.validation.CustomValidator and have a no-args constructor. The first type parameter of CustomValidator is the validator annotation. In our example this is Length. The second type parameter specifies the class for which the validator can be used. Here the Length validator can be used for String. All derivatives of the specified class are allowed as well.

public class LengthValidator implements CustomValidator<Length, String> {

    public static final int ERROR_CODE = 1;

    @Override
    public ValidationResult onValidate(Length length, String data) {
        long minLength = length.min();
        long maxLength = length.max();
        if (data == null) {
            return ValidationResult.valid();
        }
        if (minLength > -1 && data.length() < minLength) {
            return ValidationResult.invalid(ERROR_CODE, "The given data is to short. It should be between " + minLength + " and " + maxLength + " characters long.");
        }
        if (maxLength > -1 && data.length() > maxLength) {
            return ValidationResult.invalid(ERROR_CODE, "The given data is to long. It should be between " + minLength + " and " + maxLength + " characters long.");
        }
        return ValidationResult.valid();
    }
}

As you can see the method onValidate has two parameters. The first one is the validator annotation where you can grab your parameter values from and the second is the object to be validated.

The result is of type ValidationResult and allows you to return an error code and error message, when the object is invalid.

The updated schema

The database schema has being updated to represent the validators used on a column. As you can see in the following example, the validators are listed within the Attribute information of the column. The column foo has three validators and the schema also provides information about the parameters specified within this validators.

public static final IntegerAttribute FOO = new IntegerAttribute("foo", java.lang.Integer.class, 1, new ColumnValidator(org.droitatedDB.validation.Min.class, org.droitatedDB.validation.MinValidator.class, "value", 4), new ColumnValidator(org.droitatedDB.validation.Max.class, org.droitatedDB.validation.MaxValidator.class, "value", 25), new ColumnValidator(org.droitatedDB.validation.NotNull.class, org.droitatedDB.validation.NotNullValidator.class));