Data validation
Validation rule reference
The built-in validation rules, their parameters, and what makes them fail
Orbital ships with a set of validation rules in the com.orbitalhq.validation namespace. They’re built in —
there’s nothing to add to your project to use them.
Remember that declaring a rule isn’t enough on its own: a rule only runs when a @Valid scope covers it (or
when it’s declared directly on a query parameter). See validating data
for how activation works.
All rules
| Rule | Parameters | Applies to | Fails when |
|---|---|---|---|
@NotEmpty | — | strings, collections | the string is "", or the collection has no items |
@MinLength | value : Int | strings | the string is shorter than value |
@MaxLength | value : Int | strings | the string is longer than value |
@Pattern | regex : String | strings | the string doesn’t fully match regex |
@Min | value : Decimal, exclusive : Boolean = false | numbers | the number is below value — or at it, when exclusive = true |
@Max | value : Decimal, exclusive : Boolean = false | numbers | the number is above value — or at it, when exclusive = true |
@MultipleOf | value : Decimal | numbers | the number isn’t an exact multiple of value |
@MinItems | value : Int | collections | the collection has fewer than value items |
@MaxItems | value : Int | collections | the collection has more than value items |
@UniqueItems | — | collections | the collection contains duplicates |
@Email | — | strings | the string isn’t a valid email address |
@Uuid | — | strings | the string isn’t a valid UUID |
Parameters every rule accepts
Every rule inherits from com.orbitalhq.validation.ValidationRule, which gives all of them two extra
parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
message | String | the rule’s own message | Replaces the generated violation message |
severity | Severity | Error | One of Info, Warning or Error |
import com.orbitalhq.validation.Validimport com.orbitalhq.validation.MaxLengthimport com.orbitalhq.validation.Severity
@Validmodel Doc { @MaxLength(value = 3, severity = Severity.Warning, message = "too long") code : String}Severity decides whether a violation is serious enough to fail the query. With the default
threshold = Error, only Error violations reject — see
choosing a threshold.
String rules
import com.orbitalhq.validation.Validimport com.orbitalhq.validation.NotEmptyimport com.orbitalhq.validation.MinLengthimport com.orbitalhq.validation.MaxLengthimport com.orbitalhq.validation.Pattern
@Validmodel Registration { @NotEmpty username : Username inherits String @MinLength(value = 8) password : Password inherits String @MaxLength(value = 140) bio : Bio inherits String @Pattern(regex = "[A-Z]{2}[0-9]{4}") reference : Reference inherits String}@NotEmpty
Fails on an empty string, "". A whitespace-only string like " " passes — if you want to catch that,
use @Pattern.
@NotEmpty also works on collections, where it fails an empty collection.
@MinLength / @MaxLength
Character-count bounds. Both are inclusive: with @MinLength(value = 3), a 3-character string passes, and a
2-character string fails with:
Value 'ab' is shorter than the minimum length of 3 (was 2)@Pattern
Matches the whole string against a regular expression — a partial match fails. Given
@Pattern(regex = "[A-Z]{2}[0-9]{4}"):
| Value | Result |
|---|---|
AB1234 | passes |
AB1234-extra | fails — the pattern must match the entire value |
hello | fails |
Numeric rules
import com.orbitalhq.validation.Validimport com.orbitalhq.validation.Minimport com.orbitalhq.validation.Maximport com.orbitalhq.validation.MultipleOf
@Validmodel Order { @Min(value = 1) quantity : Quantity inherits Int @Min(value = 0, exclusive = true) price : Price inherits Decimal @Max(value = 100) discountPercent : DiscountPercent inherits Decimal @MultipleOf(value = 0.01) amount : Amount inherits Decimal}@Min / @Max
Bounds are inclusive by default — a value exactly on the bound passes. Set exclusive = true to make the
bound itself fail, which is how you express “must be greater than zero”:
| Declaration | 0 | 0.01 |
|---|---|---|
@Min(value = 0) | passes | passes |
@Min(value = 0, exclusive = true) | fails | passes |
@MultipleOf
Comparison is exact decimal arithmetic, not floating point, so 0.3 is a multiple of 0.1. This makes it
reliable for money — @MultipleOf(value = 0.01) means “no fractional pennies”.
A value of 0 never produces a violation.
Collection rules
import com.orbitalhq.validation.Validimport com.orbitalhq.validation.MinItemsimport com.orbitalhq.validation.MaxItemsimport com.orbitalhq.validation.UniqueItems
type Tag inherits Stringtype Contributor inherits Stringtype Category inherits String
@Validmodel Post { @MinItems(value = 2) tags : Tag[] @MaxItems(value = 10) contributors : Contributor[] @UniqueItems categories : Category[]}@MinItems / @MaxItems
Item-count bounds, both inclusive. A collection of exactly value items passes either rule.
@UniqueItems
Fails when a collection contains duplicates. It works on collections of scalars and of models — duplicate models are detected by comparing their values, so two structurally identical objects count as a duplicate.
Format rules
import com.orbitalhq.validation.Validimport com.orbitalhq.validation.Emailimport com.orbitalhq.validation.Uuid
@Emailtype EmailAddress inherits String
@Uuidtype CorrelationId inherits String
@Validmodel Contact { email : EmailAddress correlationId : CorrelationId}Format rules are a natural fit for declaring on the type rather than the field. EmailAddress is an email
address wherever it appears, so declaring the rule once means every model that uses the type gets it.
Checks the string is a plausible email address: a local part, a single @, a domain containing at least one
dot, and no whitespace.
@Uuid
Checks the string is a canonical UUID — 8-4-4-4-12 hexadecimal characters separated by hyphens.
Rules Orbital produces for you
Two rule names appear in violations without you ever declaring them. You’ll see these in the rule field of a
validation failure report:
| Rule | Reported when |
|---|---|
com.orbitalhq.validation.NotNull | A non-nullable field inside a @Valid scope is holding null |
com.orbitalhq.validation.ParseFailure | A value inside a @Valid scope couldn’t be parsed into its declared type |
NotNull is why you never declare a “required” rule — your taxonomy already says whether a field is
nullable, and @Valid enforces it. See
activating validation.
What does not produce a violation
Rules are deliberately narrow about what they apply to, so that a rule declared on a widely-reused type doesn’t cause noise everywhere it’s used:
- A rule that doesn’t apply to the value’s kind is skipped.
@MinLengthon a number, or@MinItemson a string, produces nothing — not a violation. nullnever trips a rule. Rules describe what a value must look like when it’s present. Whether the value is allowed to be absent at all is a nullability question, handled byNotNull.