Towards a JSON API for the JDK
Cay Horstmann
cay.horstmann at gmail.com
Mon May 19 14:12:55 UTC 2025
Il 19/05/25 10:13, Remi Forax ha scritto:
>> If only there was some deconstruction magic that approximates the JavaScript
>> code
>>
>> const doc = { name: "John", age: 30 }
>> const { name, age } = doc
>
> We already have that, it's called a record :)
>
> Basically, you are advocating for a mapping JsonObject <--> record.
>
> [...]
>
>>
>> Cheers,
>>
>> Cay
>>
>
> Here is a simple JsonObject mapper using java.util.json types.
> https://github.com/forax/json-object-mapper
That's interesting, but I don't think it works as a solution to read generic JSON. I have to deal with much JSON that is at best semi-structured. And anyway, databinding is is excluded from the scope of the core Java JSON API.
Let me explain in more detail what I was trying say offhandedly. For tree traversal, Jackson has isXxx, asXxx, get, path (for "safe" chaining), and JSON Pointer support. The core Java JSON library proposes to rely on pattern matching instead. With the capabilities of pattern matching today, that is unappealing. Could it get better with some of the ideas in https://openjdk.org/projects/amber/design-notes/patterns/towards-member-patterns?
Let's assume we have a factory method
var doc = JsonObject.of("name", JsonString.of("John"), "age", JsonNumber.of(30));
Could there be a matching deconstructor? It couldn't be overloads like
public inverse JsonObject of(String key1, JsonValue value1, String key2, JsonValue value2)
The deconstructor could not know which entries to pick and in what order. But similar to the regex example in the design note, one could define a "pattern object" holding the keys:
case JsonObject.withKeys("name", "age").of(JsonString.of(String name), JsonNumber.of(long age)) ->
Maybe even:
case JsonObject.withKeys("name", "age").fromUntyped(String name, Long age) ->
With nested objects:
case JsonObject.withKeys("user").of(
JsonObject.withKeys("name", "age").fromUntyped(String name, Long age)) -> { /* use name, age */ }
default -> /* deal with error */
I made some impromptu design decisions to get this far, as well as assumptions how deconstruction would eventually work. Which may well be wrong.
In Jackson, it would be
try {
JsonNode user = nestedDoc.get("user");
String name = user.get("name").asText();
int age = user.get("age").asInt();
/* use name, age */
} catch (...) { /* deal with error */ }
At first I thought the pattern matching version would be worse, but I admit that the structural safety is appealing.
Cheers,
Cay
--
Cay S. Horstmann | https://horstmann.com
More information about the core-libs-dev
mailing list