In the my world - which I am again very interested in revisiting once there
is a version of patterns I can touch - you may approach that problem in the
following way:

sealed interface Content extends JsonEncodable {
    static Content fromJson(Json json) {
        return switch (json) {
            case JsonObject obj when obj.get("pairs") != null -> new Pairs(
                    field(
                            obj,
                            "pairs",
                            pairs -> array(pairs, pair ->
Pair.fromJson(pair, string()))
                    )
            );
            case JsonObject obj when obj.get("strings") != null -> new
Strings(
                    field(obj, "strings", array(string()))
            );
            default ->
                    throw JsonDecodeException.of("Expected a top-level
\"pairs\" or \"strings\".", json);
        };
    }
}

record Pair<T>(T first, T second) {
    Json toJson(Function<T, ? extends JsonEncodable> f) {
        return Json.objectBuilder()
                .put("first", f.apply(first))
                .put("second", f.apply(second))
                .build();
    }

    static <T> Pair<T> fromJson(Json json, JsonDecoder<? extends T>
decoder) {
        return new Pair<>(
                field(json, "first", decoder),
                field(json, "second", decoder)
        );
    }
}

record Pairs(List<Pair<String>> value) implements Content {
    @Override
    public Json toJson() {
        return Json.objectBuilder()
                .put("pairs", Json.of(value, pair ->
pair.toJson(JsonString::of)))
                .build();
    }
}
record Strings(List<String> value) implements Content {
    @Override
    public Json toJson() {
        return Json.objectBuilder()
                .put("strings", Json.of(value, JsonString::of))
                .build();
    }
}

I think it is reasonable to expect/hope patterns can be an improvement on
the "yield value or throw" strategy of decoders, but I think this is
sufficient to show that this sort of task is not solely solvable via
databinding.

JSON is different from other "core capabilities" the JDK adds in that the
important factor here isn't only whether "there is an API which can
represent a JSON document," but also what form solving problems that
require JSON takes absent third-party APIs.

On Wed, May 21, 2025 at 3:56 AM Cay Horstmann <cay.horstm...@gmail.com>
wrote:

> Data binding is indeed complex because real-life JSON is messy. I reviewed
> some code in which I use Jackson data binding. Here is an example of a
> sticky issue. I have Content that's either a list of strings or a list of
> string pairs (don't ask). The JSON is
>
> { "strings": [..., ..., ... ] }
>
> or
>
> { "pairs": [ { "first", ..., "second", ... },  ..., ... ]
>
> The JavaScript client relies on the fact that exactly one of "strings" and
> "pairs" exists. No, I can't change the JSON.
>
> I deserialize into a record Content(List<String> strings,
> List<Pair<String>> pairs) {}. And tweak Jackson to not to serialize entries
> with null values. It's not pretty, but it is easier than doing tree
> navigation, since this sits deeply in an otherwise fairly regular structure.
>
> Could that work with Serialization 2.0? I suppose. Looking at
> https://www.youtube.com/watch?v=mIbA2ymCWDs, a marshaller can't
> dynamically produce either a List<String> or a List<Pair<String>>, so it
> would offer both in the Marshalled<Content> object, with one of them being
> null. I would need to tell the wire format generator to write the non-null
> one. Which is ok--that's what I do now with Jackson.
>
> Here is another common issue. You have a record TimedPoint(int x, int y,
> Instant when) {}. How do you want to serialize the Instant? As an ISO 8601
> string? Millis since the epoch? Who makes that choice? Slide 29 says "Let
> the class author be in charge". WHICH class author? Can java.time.Instant
> make a universal choice, for all possible wire formats? Surely not. Can
> TimedPoint? Maybe. Or it is the job of the wire format generator to do that
> with Marshalled<TimedPoint>?.
>
> So here is my point. If the JDK were to include a JSON data mapper, that
> data mapper is either rigid or flexible. Designing a flexible data mapper
> is hard. Serialization 2.0 would not make it any easier.
>
> My hunch is that flexible JSON data mapping is hard to do within the scope
> of the JDK. Would it follow Jakarta JSON Binding and be tied to that spec?
> Or strike out on its own? Neither seems attractive.
>
> Ethan and Rémi have presented rigid JSON mappers. They handle nothing but
> numbers, strings, booleans, maps, lists, records. Is that useful? Surely,
> for simple programs. For that, there is no reason to wait for Serialization
> 2.0. If and when that comes, it would be a natural extension.
>
> Cheers,
>
> Cay
>
> Il 20/05/25 21:46, Paul Sandoz ha scritto:
> > Data binding is a complex feature, even if some examples make it appear
> simple. Our intention is to explore alignment with the serialization 2.0
> effort, when we are ready to so. Hence, I would urge folks to be patience
> and watch out Brian and Viktor’s Devoxx 2024 talk on the topic.
> >
> > Paul.
> >
> >> On May 20, 2025, at 12:21 PM, Swaranga Sarma <sarma.swara...@gmail.com>
> wrote:
> >>
> >>> A potential advantage that we (the OpenJDK community) can more easily
> do is devise an API that resonates with direction the Java platform is
> heading, specifically around the pattern matching and serialization 2.0
> >>
> >> Right, but most of the discussion here seems to be on the low level
> tree API and how one might navigate it (perhaps using pattern matching). I
> am not seeing any discussion on the serialization/deserialization or any
> reasoning why that is not the goal of the new JEP. Basically a very focused
> and narrow API:
> >>
> >> ```
> >> var jsonStr = "..."
> >> var myRecord = Json.deserialize(jsonString, UserRecord.class); //and a
> few other variants
> >> var serialized = Json.serialize(myRecord)
> >> ```
> >>
> >> This leaves the tree API open to reimplementation later when pattern
> matching and other features are firmly in place in the JDK. I am making a
> case that this would be more immediately useful for the most common and
> simpler cases.
> >>
> >>
> >> Regards
> >> Swaranga
> >
>
> --
>
> Cay S. Horstmann | https://horstmann.com
>
>

Reply via email to