I think I see what you mean, although to me the general characterization as construction/deconstruction is too narrow - there are a zillion ways to pack-in and pack-out the tree, some partial, and some lossy etc. The canonical pack-in/out is arguably parsing and writing from and to JSON documents.
fromUptyped is way to “pack-in” the tree, transforming maps and lists, where leaf elements are directly input to the construction of JSON (leaf) values. toUptyped is the functional inverse to "pack-out”, and when we have deconstructor patterns we can more clearly and concisely express the deconstruction relationship in the switch statement e.g., perhaps like [1]. I think it a feature that they directly lean into construction and (currently implement) deconstruction of JSON values without much or any embellishment. This of course punts on the problem of dealing with present, absent, or null values of a field. Perhaps that is more suited for data binding use cases? Paul. [1] public static Object toUntyped(JsonValue src) { Objects.requireNonNull(src); return switch (src) { case JsonObject(Map<String, JsonValue> members)) -> members.entrySet().stream() .collect(LinkedHashMap::new, // to allow `null` value (m, e) -> m.put(e.getKey(), Json.toUntyped(e.getValue())), HashMap::putAll); case JsonArray(List<JsonValue> values)) -> values.stream() .map(Json::toUntyped) .toList(); case JsonBoolean(boolean value) -> value; case JsonNull _ -> null; case JsonNumber(Number value) -> value; case JsonString(String value) -> value; }; } On May 19, 2025, at 3:46 PM, Ethan McCue <et...@mccue.dev> wrote: What I mean by central in this context isn't that it's at the core of things and features are built on top of it - as you note it is a valid transformation of the hierarchy. What I mean is that absent other construction/deconstruction apis it is the most convenient avenue for those tasks. So code using the API would trend towards using it. See Remi's usage of fromUntyped elsewhere in the discussion tree. The thing that the language doesn't have yet is patterns. We have all the mechanism for creating objects. The broad issue I see is that, if we take the view that >in general< deconstruction should be the dual of construction - the mechanics for construction should probably be influenced by how you want people pulling these things apart. Basic example - JsonString.of - that is null hostile for good reason, but it is very easy to imagine wanting to write code that deals uniformly with absent, null, and string values for a field in an object. So that puts a pressure - beyond creation ergonomics - on a Json.of that is null-tolerant. Since that would be a good place for a dual pattern for pulling out a possibly nullable object member. (but still wouldn't solve for absent ones - I have a doc somewhere with like 15 options none of which inspire joy and many of which are conditional on exactly how patterns ship) On Mon, May 19, 2025, 3:55 PM Paul Sandoz <paul.san...@oracle.com<mailto:paul.san...@oracle.com>> wrote: > > This is part of why fromUntyped/toUntyped is uncomfortable - it's choosing > one particular encoding of JSON and making it central to the API. Is that > really the most important encoding? > It's one opinionated kind, a simple bi-directional mapping (embedding-projection pair) based on what the json values contain. The implementations can be entirely written less than 100 lines of code using the public API (there are more lines for the documentation). Users can easily write their own and can serve as an example with a bit more exposition in the documentation. The methods could be removed and it would not affect anything else, so it's not fundamental nor central. Paul.