Erasmus is not on Maven Central yet, so getting started means building it from source once, then using it like any Jakarta Validation provider — the API is 100 % the standard one.

Prerequisites

  • Java 25 (Temurin recommended)

  • Maven 3.9.16 — pinned via .sdkmanrc in the repo (sdk env)

  • io.vidocq:vidocq-parent:0.3.0-SNAPSHOT installed in your local Maven repository — the Erasmus reactor inherits from it with an empty relativePath, so a fresh clone does not build without it:

git clone https://codefloe.com/Vidocq/vidocq-parent.git
cd vidocq-parent
./mvnw -ntp install

Step 1 — Build from source

git clone https://codefloe.com/Vidocq/erasmus.git
cd erasmus
./mvnw -ntp install -DskipTests

This installs the 0.3.0-SNAPSHOT artifacts into your local repository.

Step 2 — Maven coordinates

<dependency>
    <groupId>io.vidocq.erasmus</groupId>
    <artifactId>erasmus-api</artifactId>
    <version>0.3.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>io.vidocq.erasmus</groupId>
    <artifactId>erasmus-core</artifactId>
    <version>0.3.0-SNAPSHOT</version>
    <scope>runtime</scope>
</dependency>

erasmus-api re-exposes the Jakarta Validation API (requires transitive jakarta.validation); erasmus-core is the engine, discovered at runtime through the spec’s ValidationProvider service — your code never touches an Erasmus class.

Step 3 — Declare the modules

module com.acme.orders {
    requires jakarta.validation;
    // erasmus-core is a runtime-only provider: no requires needed —
    // service binding finds it on the module path.
}

Step 4 — Constrain a bean

package com.acme.orders;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public class Person {

    @NotNull
    @Size(min = 2, max = 20)
    private String name;

    public Person(String name) { this.name = name; }
    public String getName()    { return name; }
}

Step 5 — Validate

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;

import java.util.Set;

try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
    Validator validator = factory.getValidator();

    Set<ConstraintViolation<Person>> violations = validator.validate(new Person("X"));

    violations.forEach(v ->
        System.out.println(v.getPropertyPath() + ": " + v.getMessage()));
    // name: size must be between 2 and 20
}

buildDefaultValidatorFactory() finds Erasmus through the standard provider discovery — the same code runs unchanged on any compliant implementation.

Next steps

  • Usage — custom constraints, composition, message interpolation.

  • Concepts — how the engine models constraint metadata.

  • TCK status — what is covered today, what is coming.