Skip to content

JDK-only stack: a JsonCodec backed by the JDK's built-in JSON API (JEP 540) #13

Open

Description

@dfa1

Goal

A TypeSafe client with zero third-party dependencies: typesafe-java-client-jdk (java.net.http) plus a new JsonCodec backed by the JDK's own JSON API from JEP 540: Simple JSON API (Incubator), instead of Jackson.

About JEP 540

  • Incubator module jdk.incubator.json, integrated, target release JDK 28.
  • Parses with Json.parse(String) into a JsonValue tree (JsonObject, JsonArray, JsonString, JsonNumber, JsonBoolean, JsonNull). Writes compact JSON via toString(), pretty-printed via Json.toDisplayString().
  • Strict RFC 8259 parsing: no comments, no trailing commas, no duplicate keys.
  • No data binding: nothing maps JSON to records or records to JSON automatically.

What it would take

  • A new module, e.g. jdk-json (or codec-jdk if Split client into its own module and align artifact names with packages #12's naming lands), implementing JsonCodec (writeValueAsString, writeValueAsPrettyString, readValue(String, Class<T>)). It would be discovered through META-INF/services like the Jackson codecs.
  • Hand-written mapping between the model and JsonValue trees, since there's no data binding. It must cover EvaluateRequest, EvaluateResponse, Question/Answer (with the type discriminator), Content (string, object or array), Model, ModelDetails, Usage and RequestId. The output must match what the Jackson codecs produce exactly.
  • ModelsResponse. DefaultTypeSafeClient asks the codec to decode its package-private ModelsResponse record, which works with Jackson only because Jackson uses reflection. A hand-written codec can't name that type, so listModels() decoding needs a codec-independent shape, for example a public type or a dedicated method on JsonCodec.
  • Build:
    • The project compiles for Java 21 (maven.compiler.release 21), and CI, Sonar and publish all run on JDK 21.
    • This module needs JDK 28+ and --add-modules jdk.incubator.json at compile, test and run time.
    • It should probably build only in a Maven profile activated on JDK ≥ 28, with a CI job on JDK 28. It must stay out of the default JDK 21 build and the BOM until it's publishable.
  • Tests: ideally pull the existing Jackson2CodecTest/Jackson3CodecTest cases into a shared test that every codec runs, so all three are checked to produce the same output. Also add an acceptance-test combination, client-jdk + JDK JSON.
  • CLI: once the JDK API is final (no longer incubating), the CLI could drop Jackson 3 and become JDK-only.

Risks

  • Incubator APIs change between JDK releases and print an incubating-module warning at startup. Publishing a codec built against one now means tracking JDK 28, 29 and later until the API becomes final.
  • Requiring JDK 28+ excludes JDK 21 users. It has to stay a separate, optional module, never the default.

Suggested approach

Prototype now to settle the mapping code and the ModelsResponse question. Hold off publishing until the API leaves incubation, or publish clearly marked as experimental.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions