Validation rules are domain-level rules executed on dirty domain objects prior to changes being sent to the database.
Each domain object has a List<ValidationRule> rules that can be added or removed to as needed.
Code generation automatically adds some basic validation rules:
public abstract class ChildCodegen ... {
...
private void addExtraRules() {
this.addRule(new NotNull<Child>(Shims.name));
this.addRule(new MaxLength<Child>(Shims.name, 100));
}
...
}
But custom/business validation rules are simple to add, either as one-off inner classes:
public class ValidationAFoo {
public ValidationAFoo() {
this.addExtraRules();
}
private void addExtraRules() {
this.addRule(new Rule<ValidationAFoo>() {
public void validate(ValidationErrors errors, ValidationAFoo foo) {
if ("bar".equals(foo.getName())) {
errors.addPropertyError(foo, "name", "must not be bar");
}
if ("baz".equals(foo.getName())) {
errors.addObjectError(foo, "is all messed up");
}
}
});
}
}
Or as higher-level, reusable rule, e.g.:
private void addExtraRules() {
this.addRule(new MustNotOverlap(Shims.children, ChildCodegen.Shims.begin, ChildCodegen.Shims.end)); // I think
}
(Note: This example was used on a previous-generation Joist-like framework to ensure that parent entities with collections of time-based entries could validate that none of the children overlapped each other and not copy/paste the boilerplate overlap code into each parent entity.)
Validation rules might eventually use bindgen-generated bindings as bindings are stateful and so can navigate object graphs while shims are stateless and can only access single-level properties.