Options overview

Spine Validation rules are expressed as Protobuf options. You annotate your .proto model with built-in options, and the Validation Compiler turns those option values into runtime checks in the generated Java code.

This page explains where the built-in options come from, how they are applied at build time, and what API you get at runtime.

Where options come from 

The built-in validation options are defined in spine/options.proto.

The file comes in the spine-base.jar artifact, which is an API dependency of the Validation runtime library (spine-validation-java-runtime.jar) added to your project by the Validation Gradle plugin.

To use an option, import the proto that defines it and annotate your fields and messages.

import "spine/options.proto";

If you need a refresher on how custom options work in Protobuf, see Protobuf custom options.

How options are applied (build time) 

Spine Validation is enforced by generated code, not by interpreting option values at runtime.

At build time:

  1. protoc compiles your .proto files into descriptors and generates Java sources.
  2. The Spine Validation Gradle plugin wires the Validation Compiler into the build.
  3. The Validation Compiler reads the compiled descriptors (including your option values) and augments protoc output with validation logic.

The result is a Java API that enforces the rules you declared in the model.

  flowchart LR
    A["<code>.proto</code><br/>&nbsp;&nbsp;+<br/><code>spine/options.proto</code>"] --> B["<b>protoc</b> <br/> (Java)"]
    B --> C["<b>Validation Compiler</b><br/>via Gradle plugin"]
    C --> D["Generated Java API<br/><code>build()</code>, <code>validate()</code>"]

What code you get (runtime) 

Generated messages and builders provide a small validation-focused API surface:

  • build() performs validation and throws ValidationException if a constraint is violated.
  • buildPartial() builds without validation.
  • validate() checks an existing instance and returns Optional<ValidationError>.

See “Using the generated code” for Java and Kotlin examples.

What does not happen 

At runtime, Spine Validation does not parse descriptor option data to decide what to validate. All checks are already translated into the generated message/builder code.

Tiny examples 

These examples are intentionally minimal. They are only meant to illustrate the “annotate with options → get runtime checks” flow.

Required field 

import "spine/options.proto";

message UserEmail {
  string value = 1 [(required) = true];
}

String pattern 

import "spine/options.proto";

message OrderId {
  string value = 1 [(pattern).regex = "^[A-Z]{3}-\\d{6}$"];
}

Numeric range 

import "spine/options.proto";

message Temperature {
  int32 kelvin = 1 [
    (min).value = "0",
    (max).value = "10000"
  ];
}

What’s next