Skip to content

Latest commit

 

History

History
272 lines (206 loc) · 8.39 KB

File metadata and controls

272 lines (206 loc) · 8.39 KB

JSON Type Definition (JTD) Validator

A Java implementation of the JSON Type Definition (JTD) specification (RFC 8927). JTD is a schema language for JSON that provides simple, predictable validation with eight mutually-exclusive schema forms.

Use Case

This interpreter-based validator is optimised for infrequent validation — loading configuration files, validating resources at startup, or one-off schema checks. Because these operations run rarely, the validated classes are unlikely to be JIT-compiled, and the interpreter's simplicity keeps startup overhead low. After validation completes, the schema and document objects are typically discarded, so the JVM is not encumbered with loaded validator classes and can focus JIT effort on the application's hot path.

For repeated hot-path validation (e.g., event processing, API gateways), consider the bytecode codegen module which generates dedicated validator classes that benefit from JIT optimisation over many invocations.

Future note: java.util.json has entered the JDK incubator (jdk.incubator.json). Once the API stabilises in the JDK itself, generated bytecode validators can depend directly on future JDK classes rather than this backport, making them even more efficient with zero library overhead.

Features

  • RFC 8927 Compliant: Full implementation of the JSON Type Definition specification
  • Eight Schema Forms: Empty, Ref, Type, Enum, Elements, Properties, Values, Discriminator
  • Stack-based Validation: Efficient iterative validation with comprehensive error reporting
  • Immutable Design: All schema types are records, validation uses pure functions
  • Rich Error Messages: Standardized error format with instance and schema paths
  • Comprehensive Testing: Includes official JTD Test Suite for RFC compliance

Quick Start

import json.java21.jtd.Jtd;
import jdk.sandbox.java.util.json.*;

// Create a JTD schema
String schemaJson = """
{
  "properties": {
    "id": { "type": "string" },
    "name": { "type": "string" },
    "age": { "type": "int32" }
  },
  "optionalProperties": {
    "email": { "type": "string" }
  }
}
""";

// Parse and validate
JsonValue schema = Json.parse(schemaJson);
JsonValue data = Json.parse("{\"id\": \"123\", \"name\": \"Alice\", \"age\": 30}");

Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, data);

if (result.isValid()) {
    System.out.println("Valid!");
} else {
    result.errors().forEach(System.out::println);
}

Schema Forms

JTD defines eight mutually-exclusive schema forms:

1. Empty Schema

Accepts any JSON value:

{}

2. Ref Schema

References a definition:

{"ref": "address"}

3. Type Schema

Validates primitive types:

{"type": "string"}

Supported types: boolean, string, timestamp, int8, uint8, int16, uint16, int32, uint32, float32, float64

Integer Type Validation

Integer types (int8, uint8, int16, uint16, int32, uint32) validate based on numeric value, not textual representation:

  • Valid integers: 3, 3.0, 3.000, 42.00 (mathematically integers)
  • Invalid integers: 3.1, 3.14, 3.0001 (have fractional components)

This follows RFC 8927 §2.2.3.1: "An integer value is a number without a fractional component."

4. Enum Schema

Validates against string values:

{"enum": ["red", "green", "blue"]}

5. Elements Schema

Validates homogeneous arrays:

{"elements": {"type": "string"}}

6. Properties Schema

Validates objects with required/optional fields:

{
  "properties": {
    "id": {"type": "string"},
    "name": {"type": "string"}
  },
  "optionalProperties": {
    "email": {"type": "string"}
  }
}

7. Values Schema

Validates objects with homogeneous values:

{"values": {"type": "string"}}

8. Discriminator Schema

Validates tagged unions:

{
  "discriminator": "type",
  "mapping": {
    "person": {"properties": {"name": {"type": "string"}}},
    "company": {"properties": {"name": {"type": "string"}}}
  }
}

Discriminator Constraints (RFC 8927 §2.2.8):

  • Mapping values must be properties schemas (not primitive types)
  • Mapped schemas cannot have nullable: true
  • Mapped schemas cannot define the discriminator key in properties/optionalProperties
  • The discriminator field is exempt from additionalProperties validation

These constraints are enforced at compile-time for predictable validation behavior.

Nullable Schemas

Any schema can be made nullable by adding "nullable": true:

{"type": "string", "nullable": true}

Definitions

Schemas can define reusable components:

{
  "definitions": {
    "address": {
      "properties": {
        "street": {"type": "string"},
        "city": {"type": "string"}
      }
    }
  },
  "properties": {
    "home": {"ref": "address"},
    "work": {"ref": "address"}
  }
}

Error Reporting

Validation errors include standardized information:

[off=45 ptr=/age via=#→field:age] expected int32, got string
  • off: Character offset in the JSON document
  • ptr: JSON Pointer to the failing value
  • via: Human-readable path to the error location

Building and Testing

# Build the module
./mvnw compile -pl json-java21-jtd -am

# Run tests
./mvnw test -pl json-java21-jtd -am

# Run RFC compliance tests
./mvnw test -pl json-java21-jtd -am -Dtest=JtdSpecIT

# Run with detailed logging
./mvnw test -pl json-java21-jtd -am -Djava.util.logging.ConsoleHandler.level=FINE

Functional Validator API

A schema can be compiled into a reusable JtdValidator -- a functional interface (JsonValue -> JtdValidationResult) suitable for stream pipelines:

import json.java21.jtd.JtdValidator;
import json.java21.jtd.JtdValidationResult;
import jdk.sandbox.java.util.json.*;

String schemaJson = """
    { "type": "string" }
    """;
JsonValue schema = Json.parse(schemaJson);

// Compile to a reusable validator (interpreter path, always available)
JtdValidator validator = JtdValidator.compileInterpreter(schema);

JtdValidationResult result = validator.validate(Json.parse("\"hello\""));
assert result.isValid();

// Use in a stream pipeline
List<JsonValue> docs = ...;
List<JsonValue> invalid = docs.stream()
    .filter(doc -> !validator.validate(doc).isValid())
    .toList();

Errors follow RFC 8927 exactly -- each error is an (instancePath, schemaPath) pair:

JtdValidationResult result = validator.validate(Json.parse("42"));
result.errors().forEach(e ->
    System.out.println(e.instancePath() + " -> " + e.schemaPath()));
// Output: "" -> "/type"

Bytecode-Generated Validators (optional, JDK 24+)

For repeated hot-path validation, the json-java21-jtd-codegen module generates dedicated validator classes via the JDK 24+ ClassFile API. Use its own JtdValidator.compileGenerated(schema) factory — a separate functional interface in the json.java21.jtd.codegen package.

Architecture

The validator uses a stack-based approach for efficient validation:

  • Immutable Records: All schema types are immutable records
  • Stack-based Validation: Iterative validation prevents stack overflow
  • Lazy Resolution: References resolved only when needed
  • Comprehensive Testing: Full RFC 8927 compliance test suite

See ARCHITECTURE.md for detailed implementation information. See JTD_STACK_MACHINE_SPEC.md for the interpreter specification. See JTD_CODEGEN_SPEC.md for the code generation specification.

RFC 8927 Compliance

This implementation is fully compliant with RFC 8927:

  • ✅ Eight mutually-exclusive schema forms
  • ✅ Standardized error format with instance and schema paths
  • ✅ Primitive type validation with proper ranges
  • ✅ Definition support with reference resolution
  • ✅ Timestamp format validation (RFC 3339 with leap seconds)
  • ✅ Discriminator tag exemption from additional properties

Performance

  • Zero allocations during validation of simple types
  • Stack-based validation prevents StackOverflowError
  • Early exit on first validation error
  • Immutable design enables safe concurrent use
  • Optional codegen (JDK 24+ build) eliminates interpreter overhead for hot-path validation

License

This project is part of the OpenJDK JSON API implementation and follows the same licensing terms.