--- name: corvus-java-evaluator description: > Work on the Java port of the V5 standalone schema evaluator (src-java/corvus-json-schema, Maven artifact io.github.corvus-dotnet:corvus-json-schema): loader, compiler, the ASM bytecode generator, results collector and annotations, the allocation tests, the conformance and annotation suites, the Kotlin smoke test, the jsonschema-benchmark and Bowtie integrations, and performance measurement. USE FOR: changing or debugging the Java evaluator, measuring it against Blaze and the other Corvus evaluators, running its Bowtie harness, releasing it to Maven Central, keeping it in parity with the C# runtime evaluator. DO NOT USE FOR: the C# runtime evaluator itself (see corvus-standalone-evaluator and docs/RuntimeEvaluator.md), the TypeScript port (corvus-typescript-evaluator). --- # Java Standalone Evaluator ## Overview `src-java/corvus-json-schema` ports the `Corvus.Text.Json.RuntimeEvaluator` pipeline to Java 17, by way of the Rust and TypeScript ports. `SchemaLoader` and `SchemaCompiler` build the node graph (`SchemaNode`) and its analyses (marking, in-place cycles, discriminators). `CodeGen` then generates one static method per node into a hidden class, with ASM shaded into the jar under `io.github.corvusdotnet.jsonschema.internal.asm`; `Evaluator` interprets the same graph for results collection, and for nodes that are not compiled. `JsonDocument` is the instance model: the UTF-8 text plus a flat `long[]` tape, two longs per value. The package README describes the design; `OPTIMIZATIONS.md` maps every optimisation to its counterpart in the C#, Rust and TypeScript evaluators. Keep it current: a technique added to any of the other evaluators should be checked off (or ruled out, with the reason) there. ## Build and test Java 17 or later; the wrapper fetches Maven. From `src-java/corvus-json-schema`: ```bash ./mvnw test # every test, then AllocationTest again without escape analysis ./mvnw test -Dtest=SuiteTest -DcorvusArgLine=-Dcorvus.jsonschema.interpret=true # the suite on the interpreter ./mvnw install -P release -Dgpg.skip # as CI does: adds the sources and javadoc jars (doclint fails on warnings) ``` The suites read the repository's `JSON-Schema-Test-Suite` submodule. Every required, optional and format test must pass (`draft4/optional/zeroTerminatedFloats.json` is excluded, as in the C# runner), and all annotation assertions. `SuiteTest` also asserts that every suite schema compiles to bytecode; a node that falls back to the interpreter is a performance bug, so don't relax that count. `MetaschemasTest` checks the embedded metaschemas (`src/main/resources`) against `src/Corvus.Text.Json/metaschema`. `src-java/kotlin-smoke` uses the installed jar from Kotlin (`./mvnw test` there after `install`), and `src-java/corvus-json-schema-bowtie` runs the Bowtie harness over IHOP on the required and annotation suites (`./mvnw package`). CI (`.github/workflows/java.yml`) runs all of these on Linux x64 and arm64, Windows and macOS, with Java 17, 21 and 25. ## Zero allocation Validation must allocate nothing in the steady state, compiled or interpreted, from a `JsonDocument`, a `String` or a `byte[]`. `AllocationTest` measures every keyword path with `ThreadMXBean.getCurrentThreadAllocatedBytes`, and runs again with `-XX:-DoEscapeAnalysis` so that a path that is only allocation-free after C2 scalar replacement fails. Add a case for every new keyword path. Scratch space comes from the `Evaluator` (its arena and buffers, found through the validator's owner-thread cache and then a `ThreadLocal`); formats read the UTF-8 bytes through `Utf8Chars` with reused matchers (`Formats.Context`). ## Generated code - HotSpot never JIT-compiles a method of more than 8000 bytes of bytecode, so one runs interpreted, often 10 times slower. `CodeGen` reads each method's size from the class file and regenerates an oversized node in its compact form (hashed name dispatch), or leaves it to the interpreter. Keep that guard in mind when generating more code inline. - To see what was generated, set `-Dcorvus.jsonschema.dump=