Live data from Hacker News

JEP 540: Simple JSON API (Now in Incubator)

openjdk.org

51–60 of 83 posts

Re: JEP 540: Simple JSON API (Now in Incubator)

#51
post #30

Earlier quoted context omitted.

I'm not involved with the design of this API, but it seems to me that the issue on the JSON generation side (where you're complaining about ceremony) is feature creep. Creating the API you want on top of the proposed one is trivial (even in user code), but then where do you stop? If you have that conversion, it seems reasonable to also support, say, sets and records; maybe even enums. Indeed, Java JSON libraries typi…

POJOs and records require more configuration (e.g. Jackson's @JsonProperty, @JsonDeserialize). That could plausibly be out of scope. But for constructing JSON out of strings, numbers, booleans, lists, and maps, there's really not that much scope to creep into. Specifically, I think it would be perfectly cromulent to have JsonArray.of() be able to support any Iterable of native Strings, Integers, Doubles, or Booleans;…

> there's really not that much scope to creep into

First, we've been in this game far too long to know that this isn't the case. Second, this is only incubation. It may well be that the team behind this feature intend to add more convenience methods but wish to do it later once the core is more battle-tested. It's always best to focus on the core first and add ornamentation once you know the core is right.

Re: JEP 540: Simple JSON API (Now in Incubator)

#52
post #43

Not supporting comments will be a mistake that haunts this API. They give an example of replacing properties files but those do have standardized comments! The proposed pre-processing step means all the comments are lost during round tripping, and the single line comments they suggest are not enough to even match JSONC. By the time those issues have userland workarounds you might as well use another library instead o…

Eh, I think it's a good tradeoff. If it losslessly supported deserializing comments/JSONC, or trailing commas, or JSON-lines, or whatever, the serialization APIs would get more complicated. Every time you serialize you'd have to decide which of several formats you were producing. Automatic round-trippability would still be impossible in that world, since e.g. "deserialize JSON-ish, set one key=value, reserialize" would then risk producing a not-strictly-JSON object that broke whatever it was sent to, so then you'd need a whole bunch of different serialization configs/settings, which would confuse newbies (either they produce something that's subtly different from what they need, or they accidentally strip out information).

As similar as all the almost-JSON formats are, I still think it's best to keep APIs single-purpose: one for JSON, one for JSON-lines, one for JSONC, and so on. It's a larger code surface, but a less potentially surprising one.

Re: JEP 540: Simple JSON API (Now in Incubator)

#53
post #39

A stated goal of the API is to have "low ceremony"; this seems like a lot of ceremony. IO.println(JsonObject.of(Map.of("providers", JsonArray.of(List.of(JsonString.of("SUN"), JsonString.of("SunRsaSign"), JsonString.of("SunEC")))))); There's gotta be a better way! Surely there could be some way of creating a JsonArray of native Java Strings, Booleans, Doubles, and Integers without requiring clients to explicitly conve…

Currently, JsonObject.of has this signature: static JsonObject of(Map map); java.lang.String and other types don't extend JsonValue, and java lacks any trait-like way to add this functionality to existing types, so you would have to change the signature to this: static JsonObject of(Map map); Now you can pass any Object in, but the typechecker can't ensure that it is convertible to json anymore. I.e. it will have to…

For the "quick one-off script" case (where Implicitly Declared Classes shine), I think the most galling ceremony in this example is explicitly converting all N items in a list of literals into JsonValues for JsonArray.

This would help a lot:

    public interface JsonArray extends JsonValue {
        static JsonArray of(JsonValue... elements) { ... }
        static JsonArray of(String... elements) { ... }
        static JsonArray of(Double... elements) { ... }
        static JsonArray of(Integer... elements) { ... }
        static JsonArray of(Boolean... elements) { ... }
    }
Then, you could at least write:

    IO.println(JsonObject.of(Map.of("providers",
        JsonArray.of("SUN", "SunRsaSign", "SunEC"))));
And for JsonObject, a little fluent builder API would probably knock out a lot of ceremony, too.

    JsonObject json = JsonObject.builder()
        .put("name", "John")
        .put("age", 30)
        .put("active", true)
        .put("providers", JsonArray.of("SUN", "SunEC"))
        .build();
The alternative today looks quite ceremonious:

    JsonObject json= JsonObject.of(Map.of(
        "name", JsonString("John"),
        "age", JsonNumber(30),
        "active", JsonBoolean(true),
        "providers", JsonArray.of(List.of(
            JsonString("SUN"),
            JsonString("SunRsaSign"),
            JsonString("SunEC")
        ))
    ));

Re: JEP 540: Simple JSON API (Now in Incubator)

#54
post #39

Earlier quoted context omitted.

Currently, JsonObject.of has this signature: static JsonObject of(Map map); java.lang.String and other types don't extend JsonValue, and java lacks any trait-like way to add this functionality to existing types, so you would have to change the signature to this: static JsonObject of(Map map); Now you can pass any Object in, but the typechecker can't ensure that it is convertible to json anymore. I.e. it will have to…

A Modest Proposal that will never be implemented: add an interface to String, Boolean, Integer, Long, Float and Double. Because all these types already implement "toString" (and I believe their toString representations are compatible with JSON), it can be a pure marker interface.

JSON String requires escaping of control characters. .toString() on a String is (hopefully) the identity.

Re: JEP 540: Simple JSON API (Now in Incubator)

#55

A stated goal of the API is to have "low ceremony"; this seems like a lot of ceremony. IO.println(JsonObject.of(Map.of("providers", JsonArray.of(List.of(JsonString.of("SUN"), JsonString.of("SunRsaSign"), JsonString.of("SunEC")))))); There's gotta be a better way! Surely there could be some way of creating a JsonArray of native Java Strings, Booleans, Doubles, and Integers without requiring clients to explicitly conve…

Yeah, I agree. The clean way of doing this is to build a json marshaling mechanism for the type system as it already exists. This is doable in Java, and some json libraries (e.g. gson) are already capable of this. I must admit I don't fully understand the motivation behind this JEP. Like when would I ever reach for this?

The motivation behind this JEP is laid out in the JEP under the section "Motivation".

As I understand that section (and I wasn't involved in writing this JEP), good and popular marshalling libraries for JSON already exist, and the JEP clearly states that it is not the goal to replace them or perform their role. The JEP says that this package may be what you'd reach for when a program only wants to do some very simple, small tasks with JSON data and the requirements and code size don't merit pulling in a fully-featured JSON library (e.g. when you're writing a one-file script, or exploring in JShell).

Re: JEP 540: Simple JSON API (Now in Incubator)

#56

A stated goal of the API is to have "low ceremony"; this seems like a lot of ceremony. IO.println(JsonObject.of(Map.of("providers", JsonArray.of(List.of(JsonString.of("SUN"), JsonString.of("SunRsaSign"), JsonString.of("SunEC")))))); There's gotta be a better way! Surely there could be some way of creating a JsonArray of native Java Strings, Booleans, Doubles, and Integers without requiring clients to explicitly conve…

FWIW, in Kotlin's native JSON library, the API is almost identical.

    val json = JsonObject(
        mapOf(
            "providers" to JsonArray(
                listOf(
                    JsonPrimitive("SUN"),
                )
            )
        )
    )

    println(json)
Of course nobody generally does it this way, usually you take a List/Map and directly serialize that with a helper

    val data = mapOf("providers" to listOf("SUN", "SunRsaSign", "SunEC"))

    val kotlinxJSON = Json.encodeToJsonElement(data)
    val jacksonJSON = ObjectMapper().writeValueAsString(data)

Re: JEP 540: Simple JSON API (Now in Incubator)

#57
post #34

I don't like this: String body = ... REST response body, which is a JSON document ... ; JsonValue json = Json.parse(body); json.get("properties").get("periods").asList().stream() .mapToInt(j -> j.get("temperature").asInt()) .average() .ifPresent(IO::println); Why am I able to call `.get(string)` or `.get(int)` on a JsonValue? Shouldn't these be on the JsonObject and JsonArray instead? > If the JsonValue instance is o…

That is indeed baffling and regrettable. Perhaps they believe that users will just hard-cast what .parse() returns to JsonObject/JsonArray/whatever, and that the resulting ClassCastException will be uglier and harder to debug than whatever errors are currently produced by calling .get() on something other than JsonObject?

Re: JEP 540: Simple JSON API (Now in Incubator)

#58

A stated goal of the API is to have "low ceremony"; this seems like a lot of ceremony. IO.println(JsonObject.of(Map.of("providers", JsonArray.of(List.of(JsonString.of("SUN"), JsonString.of("SunRsaSign"), JsonString.of("SunEC")))))); There's gotta be a better way! Surely there could be some way of creating a JsonArray of native Java Strings, Booleans, Doubles, and Integers without requiring clients to explicitly conve…

I was going to make fun of Java before even opening the page with something to the tune of `AbstractBeanJsonSimpleFactory` but looks like reality beat me to it, heh.

Re: JEP 540: Simple JSON API (Now in Incubator)

#59

A stated goal of the API is to have "low ceremony"; this seems like a lot of ceremony. IO.println(JsonObject.of(Map.of("providers", JsonArray.of(List.of(JsonString.of("SUN"), JsonString.of("SunRsaSign"), JsonString.of("SunEC")))))); There's gotta be a better way! Surely there could be some way of creating a JsonArray of native Java Strings, Booleans, Doubles, and Integers without requiring clients to explicitly conve…

There's a nice Java library called Clojure with a lightweight syntax if you need to work with data structures and concurrency in Java a lot: (println (json/generate-string {:providers ["SUN" "SunRsaSign" "SunEC"]}))

I prefer its sibling library Kotlin, from the makers of the world famous Java IDE: Jetbrains Fleet

Re: JEP 540: Simple JSON API (Now in Incubator)

#60
I find it very surprising that they went for unchecked exceptions. For JsonValueException the following rationale is given "This exception is unchecked, so that scripts and small programs are easier to read and write." But for JsonParseException there is no rationale. This is surprising especially given the pushback from openjdk members against jackson3 moving to unchecked exception.
Post reply on HN