JSON en el JDK: el JEP 540 entra en JDK 28 como incubadora
JDK 28 trae jdk.incubator.json para parsear y generar JSON sin dependencias externas. Es una incubadora, se activa con --add-modules y no pretende sustituir a Jackson.
El JEP 540, Simple JSON API, está integrado en JDK 28 como módulo de incubadora. Por primera vez puedes leer y escribir JSON con lo que trae el JDK, sin añadir nada al pom.xml. El motivo lo resume el propio JEP: añadir cualquier dependencia externa a una aplicación tiene un coste y añade riesgo.
Es una incubadora, no una preview: el módulo jdk.incubator.json se añade con --add-modules jdk.incubator.json al compilar y al ejecutar, y la API puede cambiar. No es para producción.
Leer JSON
Todo gira alrededor de JsonValue, una interfaz sellada cuyos subtipos son JsonObject, JsonArray, JsonString, JsonNumber, JsonBoolean y JsonNull. Json.parse te da la raíz y desde ahí navegas:
// java --add-modules jdk.incubator.json Weather.java
import jdk.incubator.json.*;
void main() {
JsonValue json = Json.parse("""
{"properties": {"periods": [{"temperature": 18}, {"temperature": 22}]}}
""");
json.get("properties").get("periods").asList().stream()
.mapToInt(j -> j.get("temperature").asInt())
.average()
.ifPresent(IO::println); // 20.0
}Si un miembro no existe o el tipo no es el que esperas, los métodos de acceso lanzan JsonValueException con la ruta del problema en el mensaje. Para los miembros opcionales está tryGet: thread.tryGet("waitingOn").ifPresent(...) solo actúa si el miembro existe.
Como la jerarquía es sellada, encaja con el switch de patrones. Este ejemplo es del JEP:
long tid = switch (thread.get("tid")) {
case JsonNumber jn -> jn.asLong();
case JsonString js -> Long.parseLong(js.asString());
default -> throw new JsonValueException("Unexpected type for \"tid\"");
};Generar JSON
También del JEP:
IO.println(JsonObject.of(Map.of("providers",
JsonArray.of(List.of(JsonString.of("SUN"),
JsonString.of("SunRsaSign"),
JsonString.of("SunEC"))))));Imprime {"providers":["SUN","SunRsaSign","SunEC"]}. Para una salida legible existe Json.toDisplayString(json, " ").
Lo que no hace
El JEP es muy claro: no es un objetivo sustituir a las librerías de JSON que ya existen. Deja fuera a propósito:
- El data binding (JSON a tus clases y al revés): añadiría mucha API y dispararía el coste de mantenerla.
- Una API de streaming, útil en casos concretos pero complicada para extraer datos sencillos.
- Variantes como JSON5: solo RFC 8259, y rechaza objetos con nombres de miembro duplicados.
Así que Jackson se queda donde está. Donde el JEP 540 tiene sentido es en scripts, herramientas internas y pruebas rápidas en las que meter una dependencia no compensa. Durante la incubación, el equipo quiere recoger casos de uso de generación y transformación de JSON para hacer evolucionar esa parte de la API: si lo pruebas, es buen momento para dar tu opinión.