Skip to content
Frameworks Article

Java's Built-In JSON API Isn't Coming for Jackson

JEP 540 finally puts a JSON parser in the JDK — strict, tree-only, and deliberately too small to replace anything.

Ji-ho Choi
Ji-ho Choi
Security & Cloud Editor · Jul 24, 2026 · 5 min read
Java's Built-In JSON API Isn't Coming for Jackson

Java has needed a built-in JSON parser since roughly the moment REST killed SOAP. JEP 198 promised one back in 2014, missed JDK 9, and spent a decade as a ghost in the JEP index. This week its successor finally became real: JEP 540, the Simple JSON API, reached Candidate status as an incubator module, jdk.incubator.json, authored by Naoto Sato, Paul Sandoz, Justin Lu, and Stuart Marks.

The headline writes itself — "Java finally gets JSON" — but the more interesting story is what the OpenJDK team refused to build. This is not a Jackson replacement, and the JEP says so outright: supplanting external libraries is an explicit non-goal. What's shipping is a strict, tree-only, in-memory parser with no data binding, no streaming, no comments, no trailing commas, and no tolerance for duplicate keys. After twelve years of waiting, Java is getting the smallest JSON API it could plausibly get. That restraint is mostly correct — with one caveat developers should push on during incubation.

What you actually get

The design descends from the java.util.json prototype Paul Sandoz floated on core-libs-dev in May 2025. Everything hangs off a sealed JsonValue interface with exactly six subtypes — JsonObject, JsonArray, JsonString, JsonNumber, JsonBoolean, JsonNull — which means an exhaustive switch over a parsed value needs no default arm. This is the first JDK API designed from day one for the pattern-matching Java that Amber has been building since JDK 17, and it shows.

Navigation is chainable without casts. Parsing a GitHub release payload looks like this:

JsonValue release = Json.parse(body);
String tag = release.get("tag_name").asString();
release.get("assets").asList().stream()
    .map(a -> a.get("browser_download_url").asString())
    .forEach(IO::println);

Missing members and type mismatches throw an unchecked JsonValueException carrying the full path and document position — genuinely useful when a chain four levels deep hits a snag. For schema drift there's tryGet, returning an Optional. Numbers are handled more carefully than most of the ecosystem bothers to: asInt() and asLong() succeed only when the value is exactly representable, and arbitrary-precision values survive round-tripping through BigDecimal. Coming from JavaScript's silent 2⁵³ truncation, that's a quiet win.

The strictness is the most opinionated call. RFC 8259 merely says duplicate object keys "SHOULD" be unique; JEP 540 hard-fails on them. That's the right side of history. Duplicate-key ambiguity — where a security filter reads the first occurrence and the backend reads the last — is a documented class of interoperability exploit, and every parser that "handles" duplicates gracefully keeps that class alive. A JDK parser can afford to be the strictest one in the room, because permissive alternatives are one dependency away.

What it deliberately isn't

No data binding means no mapping JSON to your records automatically. No streaming means the whole document lives in memory as a String or char[]. The Hacker News thread's loudest complaint, though, was ceremony on the output side, and it lands: generating a document means nesting JsonObject.of(Map.of("providers", JsonArray.of(List.of(JsonString.of("SUN")...)))). For an API whose stated goal is low ceremony, forcing explicit wrapping of every native Java value is a genuine miss. Ron Pressler's defense — start minimal, add conveniences based on real usage — is the standard OpenJDK playbook, and incubation exists precisely to fix this sort of thing. If you care, this is the feedback window; generation ergonomics are the single most likely thing to change before finalization.

The omissions also mean Jackson loses nothing that pays its bills. Spring Boot's stack, DTO-heavy services, streaming multi-gigabyte NDJSON — none of that is in scope. The pressure lands elsewhere: on Gson, which Google has kept in maintenance mode for years and which mostly survives on "I just need to parse a config file" use cases — exactly the territory a zero-dependency JDK API annexes. And on org.json, whose main virtue was being small. The closest precedent is the JDK 11 HttpClient: it never dethroned OkHttp in serious applications, but it quietly became the default answer for everything that didn't need one.

The timeline nobody should sugarcoat

Here's the cold water for anyone reading "incubator" as "imminent." JDK 27 is in Rampdown Phase Two with its feature set frozen — GA lands September 15, 2026, without this JEP. JEP 540 isn't yet on JDK 28's proposed-to-target list either, so the earliest it ships behind --add-modules jdk.incubator.json is March 2027. Then incubation has to run its course before anything graduates to a final java.util.json — and the Vector API just hit its twelfth incubation round, so incubator status guarantees nothing about pace. A realistic bet: finalized somewhere around JDK 29–30, meaning enterprise teams standardized on LTS releases may not touch this in anger before the next LTS after that. If your roadmap says "drop Jackson in 2027," revise it.

What you can do now: the prototype builds from the json branch of the jdk-sandbox repo, and once an EA build carries the module, exploring it is one flag away:

jshell --add-modules jdk.incubator.json

Where it actually changes things

The immediate beneficiaries aren't application developers at all. They're CLI tools and build tooling that currently shade Gson into their jars to avoid dependency conflicts. Library authors who've refused JSON features rather than impose a transitive Jackson version on downstream users. Single-file scripts, where Java has been steadily closing the gap with Python via instance main methods and java Foo.java — parsing an API response is the missing piece there, and this closes it. And the JDK itself: jcmd already emits JSON thread dumps the platform can't parse, and the JEP openly floats JSON replacing the crusty numbered-key property-file format for JDK configuration.

So no, JEP 540 won't reshape backend serialization — Jackson's moat is data binding, and OpenJDK just declined to compete with it. What it reshapes is the floor: the set of things Java can do with zero dependencies. That set has been embarrassingly thin on the world's dominant data format since 2014. Twelve years late, with the ergonomics still rough on the write path, this is nonetheless the right API built the right way — small enough to maintain forever, strict enough to trust, and shaped for the pattern-matching language Java has become since the last attempt died.

Sources & further reading

  1. JEP 540: Simple JSON API (Incubator) — openjdk.org
  2. JEP 540: Simple JSON API (Now in Incubator) — news.ycombinator.com
  3. JDK 27 Project Page — openjdk.org
  4. Towards a JSON API for the JDK — mail.openjdk.org
Ji-ho Choi
Written by
Ji-ho Choi · Security & Cloud Editor

Ji-ho covers the increasingly tangled overlap between cloud architecture and security, drawing on a background as a penetration tester to keep his reporting grounded in real-world attack paths. He never lets a vendor claim go unquestioned and insists that every buzzword come with a proof of concept.

Discussion 2

Join the discussion

Sign in or create an account to comment and vote.

Maya Ito @opensource_maya · 6 days ago

i'm skeptical that a tree-only, read-only API actually solves the problem it took 10 years to ship. most real apps need mutation, streaming, or both—and if devs still need jackson for anything non-trivial, it doesn't reduce the ecosystem fragmentation that justifies adding it to the jdk in the first place. feels like it's splitting the difference instead of making a choice.

Kaidaira @kaidaira · 6 days ago

yeah, this feels like the worst outcome. either go minimal and useful for the 80% case, or admit you need a real solution. splitting the difference just means everyone has to know three JSON libraries now.

Related Reading