JEP 540: Java Finally Gets a Native JSON API (What You Need to Know)
JEP 540 brings a Simple JSON API to the JDK as an incubator module. Learn what it does, what it doesn't do, code examples, and how it compares to Jackson and Gson.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →JEP 540: Java Finally Gets a Native JSON API (What You Need to Know)
For nearly three decades, parsing JSON in Java has meant picking an external library — Jackson, Gson, Moshi, or the org.json artifact — and adding a dependency. Every other major language has had native JSON support for years: JavaScript has JSON.parse(), Python has json.loads(), Go has encoding/json. Java has had nothing.
JEP 540, Simple JSON API (Incubator), is the proposal that changes this. Elevated to Candidate status in July 2026 and targeting JDK 28, it adds lightweight JSON parsing and generation directly to the JDK as an incubator module. No external dependency. No Maven coordinate. Just --add-modules jdk.incubator.json.
Here's what it does, what it doesn't, and how to use it before it ships.
Why Java Never Had Native JSON
The absence wasn't accidental. The Java ecosystem already had excellent libraries — Jackson alone has billions of monthly Maven downloads — and adding a standard API risked fragmenting the ecosystem or making an opinionated choice that aged badly.
JEP 198 (Light-Weight JSON API) was the first attempt, proposed back in 2014. It stalled. The JSON landscape at the time was still consolidating, and OpenJDK leadership chose to wait.
By 2026, the calculus changed:
- JSON is infrastructure, not a library choice. Nearly every Java service reads and writes JSON for REST APIs, configuration, LLM integration, or event streaming.
- The boilerplate tax is real. Adding Jackson for a microservice that just needs to read a config file pulls in 10+ transitive dependencies.
- GraalVM native-image needs explicit reflection configuration for Jackson/Gson. A JDK-native API with no reflection sidesteps this entirely.
- Scripting and small tools suffer most —
jshellusers, quick CLI utilities, and small Lambda functions all have disproportionate overhead from dependency management.
JEP 540 doesn't try to replace Jackson. It covers the 80% case.
What JEP 540 Provides
The API is deliberately minimal, designed strictly around RFC 8259 compliance. It provides:
- Parsing:
Json.parse(String)andJson.parse(InputStream)to produce aJsonValue - Value access: typed accessors on
JsonValue—asString(),asInt(),asLong(),asDouble(),asBoolean(),asArray(),asObject() - Generation:
JsonObject.of(...),JsonArray.of(...), andJsonValue.of(...)factory methods plus atoString()/toJson()serialization path - Navigation: map-style access for objects, index-style for arrays, with explicit null handling
What it does not provide:
- Object mapping (no
@JsonProperty, noreadValue(json, MyClass.class)) - Schema validation
- Date/time type handling
- Polymorphic type resolution
- Custom serializers/deserializers
- Streaming parsers for large documents
For all of the above, Jackson and Gson remain the right tools.
Code Examples
> Note: JEP 540 is in Candidate status as of July 2026. These examples reflect the proposed API as described in the JEP. The exact method names may change before the final JDK 28 release. Enable with --add-modules jdk.incubator.json.
Parsing an API Response
import jdk.incubator.json.Json;
import jdk.incubator.json.JsonObject;
import jdk.incubator.json.JsonValue;
String response = """
{
"model": "gpt-4o",
"temperature": 0.7,
"choices": [
{ "text": "Hello, world!", "finish_reason": "stop" }
]
}
""";
JsonValue root = Json.parse(response);
JsonObject obj = root.asObject();
String model = obj.get("model").asString(); // "gpt-4o"
double temp = obj.get("temperature").asDouble(); // 0.7
JsonObject firstChoice = obj.get("choices").asArray().get(0).asObject();
String text = firstChoice.get("text").asString(); // "Hello, world!"
System.out.println(model + " — " + text);
Compare this to the Jackson equivalent for the same task:
// Jackson — same parse, more boilerplate
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response);
String model = root.get("model").asText();
double temp = root.get("temperature").asDouble();
For simple read-only parsing, the new API and Jackson are close in verbosity. The difference is zero dependencies.
Reading a Config File
One of the most common use cases for a "simple" JSON API is reading configuration at startup:
import java.nio.file.Files;
import java.nio.file.Path;
import jdk.incubator.json.Json;
import jdk.incubator.json.JsonObject;
JsonObject config = Json.parse(
Files.readString(Path.of("config.json"))
).asObject();
String dbHost = config.get("database").asObject()
.get("host").asString();
int dbPort = config.get("database").asObject()
.get("port").asInt();
boolean debug = config.get("debug").asBoolean();
No ObjectMapper singleton, no Jackson dependency, no reflection config for GraalVM. This is the use case JEP 540 is purpose-built for.
Constructing JSON
import jdk.incubator.json.JsonObject;
import jdk.incubator.json.JsonArray;
import jdk.incubator.json.JsonValue;
JsonObject payload = JsonObject.of(
"model", JsonValue.of("gpt-4o-mini"),
"temperature", JsonValue.of(0.3),
"messages", JsonArray.of(
JsonObject.of(
"role", JsonValue.of("user"),
"content", JsonValue.of("Fix this JSON: {broken: true,}")
)
)
);
String json = payload.toJson();
// {"model":"gpt-4o-mini","temperature":0.3,"messages":[{"role":"user","content":"Fix this JSON: {broken: true,}"}]}
Handling Null Safely
JSON null is a first-class value in RFC 8259. JEP 540 distinguishes between a missing key and a key whose value is JSON null:
JsonObject obj = Json.parse("{\"name\": null, \"score\": 42}").asObject();
JsonValue name = obj.get("name");
if (name.isNull()) {
System.out.println("name is JSON null");
}
// Missing key returns null (Java null), not JsonValue.NULL
JsonValue missing = obj.get("notAKey");
if (missing == null) {
System.out.println("key does not exist");
}
This distinction — JSON null as JsonValue.NULL vs. missing key as Java null — is more explicit than Jackson's JsonNode.isMissingNode() pattern.
Enabling the Incubator Module
Since JEP 540 ships as an incubator module, it requires explicit opt-in:
Command line:java --add-modules jdk.incubator.json MyApp.java
Maven (maven-compiler-plugin):
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>--add-modules</arg>
<arg>jdk.incubator.json</arg>
</compilerArgs>
</configuration>
</plugin>
Gradle (build.gradle.kts):
tasks.withType<JavaCompile> {
options.compilerArgs.addAll(listOf("--add-modules", "jdk.incubator.json"))
}
tasks.withType<JavaExec> {
jvmArgs("--add-modules", "jdk.incubator.json")
}
JShell (for prototyping):
jshell --add-modules jdk.incubator.json
> Important: Incubator modules are not stable. The API will change between JDK early-access builds and the final release, and may be promoted, modified, or withdrawn entirely based on feedback. Do not use incubator features in production libraries or published artifacts.
How It Compares to Existing Libraries
| Feature | JEP 540 | Jackson | Gson | org.json |
|---|---|---|---|---|
| No external dependency | ✅ | ❌ | ❌ | ❌ |
| RFC 8259 parse/generate | ✅ | ✅ | ✅ | ✅ |
| Object mapping | ❌ | ✅ | ✅ | ❌ |
| Schema validation | ❌ | ❌ (plugin) | ❌ | ❌ |
| Streaming parser | ❌ | ✅ | ✅ | ❌ |
| GraalVM native (no config) | ✅ | ❌ (needs reflect-config) | ❌ | ❌ |
| Production stability | Incubator | ✅ | ✅ | ✅ |
| Annotation-driven mapping | ❌ | ✅ | ✅ | ❌ |
The two aren't in competition. Most teams will end up using both — JEP 540 for utilities and internal tooling, Jackson for the main application layer.
The Malformed JSON Problem (Still Yours to Solve)
JEP 540's parser is strict RFC 8259 compliance only. It throws on any malformed input: trailing commas, single-quoted strings, unquoted keys, JavaScript comments, truncated payloads, or the broken JSON that LLMs occasionally emit.
If you're parsing JSON from external sources — REST APIs you don't control, LLM outputs, user-submitted data, or legacy systems — you'll still need a repair step before calling Json.parse().
// Pattern: repair first, then parse with JEP 540
String raw = fetchFromExternalApi(); // may be malformed
String repaired = AiJsonMedic.repair(raw); // or use /json-repair API
JsonObject parsed = Json.parse(repaired).asObject();
You can also validate JSON online before wiring up your parser, or use the AI JSONMedic repair tool to fix malformed JSON in one click.
For LLM-specific JSON failures — truncated structured outputs, Python-literal booleans, markdown-fenced responses — see our guide on LLM structured output JSON repair and local LLM JSON output debugging.
What Happens After Incubator?
The incubator process means JEP 540 is requesting broad developer feedback before standardization. There are a few possible outcomes:
- Promoted to standard: API graduates to
java.jsonor similar in a future JDK release (likely JDK 29 or 30 if the incubation goes well) - Modified: Based on feedback, the API surface changes significantly before promotion
- Withdrawn: If the OpenJDK community decides the tradeoffs aren't right (as happened with JEP 198 in 2014)
The HN thread on JEP 540 (99 points, active discussion) suggests developer appetite is high. The main criticism — that it doesn't include object mapping — is by design, and the JEP authors have been clear that's not the goal.
Key Takeaways
- JEP 540 is real and moving fast. Candidate status + JDK 28 targeting + ADTmag/InfoQ coverage in July 2026 means this is on the roadmap, not vaporware.
- It covers the 80% case. Parse, navigate, generate. No mapping, no schema, no streaming.
- Zero dependencies. That alone makes it worth it for utilities, CLIs, Lambda functions, and GraalVM native images.
- Not production-ready yet. Incubator = API unstable. Watch the JEP 540 page and JDK 28 early-access builds.
- Jackson isn't going anywhere. For anything complex, Jackson is still the answer. JEP 540 removes the need for it in simple cases.
Follow the OpenJDK mailing list and JDK 28 EA builds if you want to test the API as it evolves.
> JSON broken before it even reaches the parser? The AI JSONMedic repair tool handles trailing commas, single quotes, truncated LLM outputs, and 20+ other malformation types — paste and fix in seconds.
Still dealing with broken JSON?
Paste it in and get it fixed in under 1 second — free, no signup, no install. Works with ChatGPT, Claude, n8n, and any AI output.
Fix My JSON Free →Related Articles