Skip to main content
Some rules are not about one field but about how fields relate: pay by pix key or by IBAN, never both; an IBAN needs its BIC; the total is the amount plus the fee. Validity has a word for the common ones, and constraint { } for the rest.
Transfer.kt
A transfer by IBAN with no BIC and a wrong total breaks two rules: And one that has both a pix key and an IBAN breaks exactlyOneOf:

Presence rules

These rules count how many of the properties are filled, that is, not null: Each violation has the code of its rule, a message that lists the properties in {fields}, and a fields entry in its metadata with the properties to act on. A form can highlight exactly those fields. The violation is about the object, so its path is empty. Give it a path to put it on a section of a form:
A property given twice counts once. A count below zero, or above the number of properties, throws IllegalArgumentException when the rules run, since it is a mistake in the rules, not in the data.

constraint, for any rule

constraint { } in the validation block checks any condition about the object. It reports its violation on a property:
The path is the name of the property, and {value} in the message is its value. When the rule is about no property in particular, give it a path, or leave the path empty for the object itself:
Stay.kt
The code is empty unless you give one. Give every rule of your own a code: it is what programs, such as a front end that translates messages, rely on.

A rule that depends on another field

A constraint inside a property’s block can read the other fields too, since they are in scope. The violation is then on that property:
When the other field is null, equalTo and after check nothing, so the rule does not fail twice for one missing value: required on that field reports it.