diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 120000b..25ef45b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,11 +13,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Set up JDK 24 + - name: Set up JDK 25 uses: actions/setup-java@v4 with: distribution: oracle - java-version: '24' + java-version: '25' cache: 'maven' - name: Build and verify diff --git a/jdt2jar/Dockerfile b/jdt2jar/Dockerfile index 19433ff..959a1f6 100644 --- a/jdt2jar/Dockerfile +++ b/jdt2jar/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -FROM eclipse-temurin:24-jdk AS build +FROM eclipse-temurin:25-jdk AS build WORKDIR /build COPY . . RUN ["./mvnw", "-pl", "jdt2jar", "-am", "package", "-DskipTests", "-Dsurefire.failIfNoSpecifiedTests=false"] @@ -10,6 +10,7 @@ RUN ["mkdir", "-p", "/empty-work/tmp", "/empty-app"] FROM gcr.io/distroless/base-debian13:nonroot COPY --from=build --chown=65532:65532 /empty-work /work COPY --from=build --chown=65532:65532 /empty-app /app +WORKDIR /work ENV JAVA_TOOL_OPTIONS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.io.tmpdir=/work/tmp -XX:+ExitOnOutOfMemoryError" COPY --from=build /opt/jre /jre COPY --from=build /build/jdt2jar/target/jdt2jar.jar /app/jdt2jar.jar diff --git a/jdt2jar/README.md b/jdt2jar/README.md index 5768c7b..8aef2d2 100644 --- a/jdt2jar/README.md +++ b/jdt2jar/README.md @@ -1,14 +1,14 @@ # jdt2jar -`jdt2jar` compiles a JTD schema into a standalone validator JAR at build time. The generated JAR runs on JDK 21+ with no JDK 24+ runtime dependency. +`jdt2jar` compiles a JTD schema into a standalone validator JAR at build time. The generated JAR runs on JDK 21+ with no JDK 25+ runtime dependency. ## Use Case This tool bridges the gap between the interpreter and codegen paths: - **Interpreter** ([`json-java21-jtd`](../json-java21-jtd/README.md)): ideal for infrequent config parsing — simple, no build step, runs on JDK 21+. -- **Codegen** ([`json-java21-jtd-codegen`](../json-java21-jtd-codegen/README.md)): ideal for repeated hot-path validation — ~9x faster, but requires JDK 24+ at runtime. -- **jdt2jar**: pre-compiles schemas into validator JARs at build time (using JDK 24+), then deploys them to any JDK 21+ runtime. Best for CI/CD pipelines, distroless containers, or environments where you want JIT-optimised validators without shipping a JDK 24+ runtime. +- **Codegen** ([`json-java21-jtd-codegen`](../json-java21-jtd-codegen/README.md)): ideal for repeated hot-path validation — ~9x faster, but requires JDK 25+ at runtime. +- **jdt2jar**: pre-compiles schemas into validator JARs at build time (using JDK 25+), then deploys them to any JDK 21+ runtime. Best for CI/CD pipelines, distroless containers, or environments where you want JIT-optimised validators without shipping a JDK 25+ runtime. > **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. @@ -35,16 +35,13 @@ A minimal distroless container image is available for offline schema compilation ### Pre-built Image (GitHub Container Registry) ```bash -# Pull the latest image docker pull ghcr.io/simbo1905/java.util.json.java21/jdt2jar:latest - -# Pull a specific release version -docker pull ghcr.io/simbo1905/java.util.json.java21/jdt2jar:2026.02.05 +docker pull ghcr.io/simbo1905/java.util.json.java21/jdt2jar:2026.05.20 ``` ### Build Locally -Requires Docker and JDK 24+ (for the build stage). Build from the repository root: +Requires Docker and JDK 25+ (for the build stage). Build from the repository root: ```bash docker build -t jdt2jar -f jdt2jar/Dockerfile . @@ -52,31 +49,38 @@ docker build -t jdt2jar -f jdt2jar/Dockerfile . ### Usage +The container's working directory is `/work`. Mount your project directory there: + +```bash +docker run --rm -v "$(pwd):/work" jdt2jar:latest schema.jtd.json --output schema-validator.jar --main +``` + +Validate a payload with the generated JAR: + +```bash +java -jar schema-validator.jar --validate payload.json +``` + +Or validate inside a container: + +```bash +docker run --rm -v "$(pwd):/work" --entrypoint /jre/bin/java jdt2jar:latest -jar /work/schema-validator.jar --validate /work/payload.json +``` + +### Helper Script + +For environments where volume mounts are restricted (e.g., Colima on macOS with projects outside `~/`), use the helper script: + ```bash -# Show help -docker run --rm ghcr.io/simbo1905/java.util.json.java21/jdt2jar:latest --help - -# Compile a schema to a validator JAR (using docker cp for file I/O) -cid=$(docker create --name jdt2jar-build ghcr.io/simbo1905/java.util.json.java21/jdt2jar:latest /work/person.jtd.json --output /work/person-validator.jar --main) -docker cp person.jtd.json jdt2jar-build:/work/person.jtd.json -docker start -a jdt2jar-build -docker cp jdt2jar-build:/work/person-validator.jar . -docker rm jdt2jar-build - -# Validate a payload with the generated JAR -java -jar person-validator.jar --validate payload.json -# Or validate inside a container -cid=$(docker create --name jdt2jar-validate --entrypoint /jre/bin/java ghcr.io/simbo1905/java.util.json.java21/jdt2jar:latest -jar /work/person-validator.jar --validate /work/payload.json) -docker cp person-validator.jar jdt2jar-validate:/work/person-validator.jar -docker cp payload.json jdt2jar-validate:/work/payload.json -docker start -a jdt2jar-validate -docker rm jdt2jar-validate +./scripts/jdt2jar.sh schema.jtd.json --output schema-validator.jar --main ``` +The script syncs source to `~/tmp/jdt2jar-work`, runs the container, and syncs output back. + ### Image Properties - **Base**: `gcr.io/distroless/base-debian13:nonroot` -- **Runtime**: jlink-minimized JDK 24 (~40 MB) +- **Runtime**: jlink-minimized JDK 25 LTS (~40 MB) - **Total size**: ~111 MB disk / ~31 MB content - **User**: `nonroot` (uid 65532) - **Shell**: none (distroless) diff --git a/scripts/jdt2jar.sh b/scripts/jdt2jar.sh new file mode 100755 index 0000000..7f979cb --- /dev/null +++ b/scripts/jdt2jar.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# jdt2jar helper script for environments where volume mounts are restricted +# (e.g., Colima on macOS with projects outside ~/). +# +# Usage: +# ./scripts/jdt2jar.sh [options...] +# +# Example: +# ./scripts/jdt2jar.sh .tmp/test.jtd.json --output .tmp/test.jar --main + +set -euo pipefail + +WORK_DIR="$HOME/tmp/jdt2jar-work" +IMAGE="${JDT2JAR_IMAGE:-jdt2jar:latest}" + +mkdir -p "$WORK_DIR" + +# Sync source (respecting .gitignore) +rsync -a --filter=':- .gitignore' --exclude='.git/' . "$WORK_DIR/" + +# Run jdt2jar in container +docker run --rm -v "$WORK_DIR:/work" "$IMAGE" "$@" + +# Sync output back (any new .jar or .java files in the work dir) +rsync -a --include='*.jar' --include='*.java' --exclude='*' "$WORK_DIR/" ./