22 — Advanced

Custom Validation Rules

Extend the ValidationRule base class to create your own domain-specific validators. Each custom rule defines its error code, severity, error message, and validation logic using @Given and @Otherwise annotations.

ValidationRule Base Class

The ValidationRule base class provides the following properties:

errorCode

Unique identifier for the validation error

severity

FATAL, ERROR, WARNING, or INFO

errorMessage

Template message with placeholders

defaultMessage

Fallback message when template fails

Example: Phone Number Validator

@Rule(name = "PhoneNumberValidationRule")
public class PhoneNumberValidationRule extends ValidationRule {

    private final String fieldName;

    public PhoneNumberValidationRule(String fieldName) {
        super("phoneNumber.invalid", Severity.ERROR,
              "${fieldName} must be a valid phone number.",
              "Value must be a valid phone number.");
        this.fieldName = fieldName;
    }

    @Given
    public boolean isValid(@Param("fieldName") String value) {
        if (value == null) return true;  // Let NotNull handle nulls
        return value.matches("^\\+?[1-9]\\d{1,14}$");
    }

    @Otherwise
    public void otherwise(RuleViolations ruleViolations) {
        ruleViolations.add(getRuleName(), getErrorCode(),
            getSeverity(), getErrorMessage());
    }
}

Using the Custom Rule

Rule rule = Rule.builder().build(new PhoneNumberValidationRule("phone"));

RuleViolations violations = new RuleViolations();
rule.run(phone -> "not-a-phone", ruleViolations -> violations);

violations.hasErrors(); // true

Lambda-Based Validation: SuppliedValidationRule

For simpler cases, use SuppliedValidationRule to create a validator from a lambda without writing a full class:

Condition check = condition((String email) ->
    email != null && email.contains("@company.com"));

SuppliedValidationRule rule = new SuppliedValidationRule(
    check, "corporate.email", Severity.ERROR,
    "Must use a corporate email", "Must use a corporate email");

Severity Levels

Customize the severity of your validation rules to control how violations are treated:

Severity Description
Severity.FATALCritical error that should halt processing
Severity.ERRORValidation failure that must be corrected
Severity.WARNINGPotential issue that should be reviewed
Severity.INFOInformational notice, not a failure

Customizing Error Codes & Messages

Error codes should follow a dot-separated naming convention (e.g., phoneNumber.invalid, email.corporate). Error messages support template placeholders like ${fieldName} that are resolved at runtime, while the default message serves as a fallback when template resolution fails.