<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p><br>
      Great work.</p>
    <p><br>
    </p>
    <p>I feel the elephant in the room needs to addressed: JSON
      comments. I haven't tested the proposed lib but I cannot see it
      mentioned so I'm assuming that comments are not supported.<br>
    </p>
    <p>For better or worse, the use of jsonc (JSON with comments) is
      everywhere in some ecosystems. Unsurprisingly this happens often
      when JSON is used as a config file format. Looking at you,
      Microsoft.</p>
    <p>It would be nice if the JDK's build-in JSON parser at least
      recognized this.</p>
    <p>I'm well aware that comments are frowned upon in JSON and not
      part of neither the spec at <a class="moz-txt-link-abbreviated" href="http://www.json.org">www.json.org</a> nor the RFC-8259.</p>
    <p>Yet, I advocate the JDK JSON library should optionally allow
      comments to be ignored when PARSING. This should be an opt-in
      feature that would technically treat comments as whitespace during
      the parsing process.<br>
    </p>
    <p>This would also be in line with what many other parsers do. For
      example, Jackson has "ALLOW_COMMENTS" feature [1]. Also, by
      comparison, the build-in parser in the .NET world, known as
      System.Text.Json, also supports this [2]. <br>
    </p>
    <p><br>
    </p>
    <p><br>
    </p>
    <p>The "discoverer" of JSON, Douglas Crowford, had this to say [3]
      on the topic:</p>
    <p><br>
    </p>
    <p>[QUOTE]<br>
    </p>
    <p>I removed comments from <abbr title="JavaScript Object Notation">JSON</abbr>
      because I saw people were using them to hold parsing directives, a
      practice which would have destroyed interoperability. I know that
      the lack of comments makes some people sad, but it shouldn't. </p>
    <p>Suppose you are using <abbr title="JavaScript Object Notation">JSON</abbr>
      to keep configuration files, which you would like to annotate. Go
      ahead and insert all the comments you like. Then pipe it through
      JSMin before handing it to your <abbr
        title="JavaScript Object Notation">JSON</abbr> parser.</p>
    <p> [/QUOTE]</p>
    <p></p>
    <p><br>
    </p>
    <p>By not having the ability to ignore comments when parsing we
      would effectively force users to use another parser first or a
      minifier. I doubt beginners would appreciate that. <br>
    </p>
    <p><br>
    </p>
    <p>BTW: The test suite already has tests for comments.</p>
    <p><br>
    </p>
    <p>/Lars<br>
    </p>
    <p><br>
    </p>
    <p>[1]:
<a class="moz-txt-link-freetext" href="https://www.javadoc.io/static/com.fasterxml.jackson.core/jackson-core/2.19.0/com/fasterxml/jackson/core/JsonParser.Feature.html#ALLOW_COMMENTS">https://www.javadoc.io/static/com.fasterxml.jackson.core/jackson-core/2.19.0/com/fasterxml/jackson/core/JsonParser.Feature.html#ALLOW_COMMENTS</a></p>
    <p></p>
    <p>[2]:
<a class="moz-txt-link-freetext" href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonreaderoptions?view=net-9.0#properties">https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonreaderoptions?view=net-9.0#properties</a></p>
    <p>[3]:
      <a class="moz-txt-link-freetext" href="https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr">https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr</a></p>
    <p><br>
    </p>
    <p><br>
    </p>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 16/05/2025 01.44, Ethan McCue wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CA+NR86gt3GNjDPS2m-2wha5AwgumMvBRxKw+bwgTCNQ1xCiDfg@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr">I present for your consideration the library I made
        when spiraling about this problem space a few years ago<br>
        <br>
        <a href="https://github.com/bowbahdoe/json" target="_blank"
          moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/bowbahdoe/json</a><br>
        <br>
        <a
href="https://javadoc.io/doc/dev.mccue/json/latest/dev.mccue.json/dev/mccue/json/package-summary.html"
          target="_blank" moz-do-not-send="true"
          class="moz-txt-link-freetext">https://javadoc.io/doc/dev.mccue/json/latest/dev.mccue.json/dev/mccue/json/package-summary.html</a><br>
        <br>
        Notably missing during the design process here were patterns,
        hence the JsonDecoder design. I haven't been able to evaluate
        how patterns affect that on account of them not being out.<br>
        <br>
        I will more thoroughly peruse the draft of java.util.json at a
        later date, but my initial observations/comments:<br>
        <br>
        * I am not sure having JsonValue be distinct from Json has
        value.<br>
        * toUntyped feels a little strange to me - the only type
        information presumably lost is the sealed-ness of the hierarchy.
        The interplay between that and toNumber is also a little
        unnerving.<br>
        * One notion that I found helpful was that a class could be
        "json encodable," meaning there is a method to call to obtain a
        canonical json representation.<br>
        <br>
        <font face="monospace">record Person(String name) implements
          JsonEncodable {</font><br>
        <font face="monospace">    </font><a class="gmail_plusreply"
          id="m_-2004856809941181964plusReplyChip-0"
          style="font-family:monospace" moz-do-not-send="true">@Override<br>
        </a><font face="monospace">    public Json toJson() {</font><br>
        <font face="monospace">        return Json.objectBuilder()</font><br>
        <font face="monospace">            .put("namen", name)</font><br>
        <font face="monospace">            .build();</font><br>
        <font face="monospace">    }</font><br>
        <font face="monospace">}</font><br>
        <br>
        <font face="arial, sans-serif">Which helper methods like </font><font
          face="monospace">Json#of(List<? extends JsonEncodable>)</font><font
          face="arial, sans-serif"> could make use of. </font><font
          face="monospace">Json</font><font face="arial, sans-serif"> itself
          (</font><font face="monospace">JsonValue</font><font
          face="arial, sans-serif"> in your prototype) could then have a
          vacuous implementation.<br>
          <br>
          * Terminology wise - I went with reading/writing for the
          actual parsing/generation of json and encoding/decoding for
          the mapping of those representations to/from specific classes.
          The merits are not top of mind, just noting the difference.
          read/write vs parse/toString+toDisplayString<br>
          * One thing I did was make the helper methods in </font><font
          face="monospace">Json</font><font face="arial, sans-serif"> null
          tolerant and the ones in the specific subtypes like </font><font
          face="monospace">JsonString</font><font
          face="arial, sans-serif"> not. This was because from what I
          saw of usages of javax.json/jakarta.json that nullability was
          a footgun and correcting for it required changes to code
          structure (breaking up builder chains with </font><font
          face="monospace">if (x != null)</font><font
          face="arial, sans-serif"> checks)<br>
        </font>* The functionality you want from <font face="monospace">JsonNumber
        </font><font face="arial, sans-serif">could be achieved by
          making it just extend </font><font face="monospace">Number (</font><a
href="https://github.com/bowbahdoe/json/blob/main/src/main/java/dev/mccue/json/JsonNumber.java"
          target="_blank" moz-do-not-send="true"
          class="moz-txt-link-freetext">https://github.com/bowbahdoe/json/blob/main/src/main/java/dev/mccue/json/JsonNumber.java</a>)
        instead of a bespoke <font face="monospace">toNumber</font><font
          face="arial, sans-serif">. You need the extra methods to go to
          big decimal and co, but it's just an extension to the behavior
          of Number at that point.<br>
        </font>* JsonObject and JsonArray could implement Map<String,
        Json> and List<Json> respectively. This lowers the need
        for toUntyped() - since presumably one of the use cases for that
        is turning the json tree into something that more generic
        map/list traversal code can handle. It also complicates any lazy
        loading somewhat.<br>
        * Assuming patterns can be placed on interfaces, you might want
        to consider something similar to <font face="monospace">JsonDecoder</font><font
          face="arial, sans-serif">, but with a pattern instead of a
          method that throws an exception.<br>
        </font><br>
        <span style="font-family:monospace">// Where here fromJson would
          box up the logic for testing and extracting from each element
          in the array.</span><br>
        <font face="monospace">List<Person> people = array(json,
          Person::fromJson);<br>
        </font><br>
        * I don't think there is sufficient cause for anything to be
        non-sealed at this point.<br>
        * JsonBoolean and JsonNull do not have reasonable alternative
        implementations - as far as I can imagine, maybe i'm wrong - so
        maybe those can just be final classes?<br>
        * If you seal up the whole hierarchy then its pretty trivial to
        make it serializable (<a
href="https://github.com/bowbahdoe/json/blob/main/src/main/java/dev/mccue/json/serialization/JsonSerializationProxy.java"
          moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/bowbahdoe/json/blob/main/src/main/java/dev/mccue/json/serialization/JsonSerializationProxy.java</a>)<br>
        <br>
        <br>
        <br>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Thu, May 15, 2025 at
          11:29 PM Remi Forax <<a href="mailto:forax@univ-mlv.fr"
            target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">forax@univ-mlv.fr</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote"
style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi
          Paul,<br>
          yes, not having a simple JSON API in Java is an issue for
          beginners.<br>
          <br>
          It's not clear to me why JsonArray (for example) has to be an
          interface instead of a record ?<br>
          <br>
          I understand why Json.parse() only works on String and char[]
          but the API make it too easy to have many performance issues.<br>
          I think you need versions using a Reader and a Path.<br>
          Bonus point, if there is a method walk() that also returns a
          JsonValue but the List/Map inside JsonArray/JsonObject are
          populated lazily.<br>
          <br>
          Minor point: Json.toDisplayString() should takes a second
          parameters indicating the number of spaces used for the
          indentation (like JSON.stringify in JS).<br>
          <br>
          regards,<br>
          Rémi<br>
          <br>
          ----- Original Message -----<br>
          > From: "Paul Sandoz" <<a
            href="mailto:paul.sandoz@oracle.com" target="_blank"
            moz-do-not-send="true" class="moz-txt-link-freetext">paul.sandoz@oracle.com</a>><br>
          > To: "core-libs-dev" <<a
            href="mailto:core-libs-dev@openjdk.org" target="_blank"
            moz-do-not-send="true" class="moz-txt-link-freetext">core-libs-dev@openjdk.org</a>><br>
          > Sent: Thursday, May 15, 2025 10:30:42 PM<br>
          > Subject: Towards a JSON API for the JDK<br>
          <br>
          > Hi,<br>
          > <br>
          > We would like to share with you our thoughts and plans
          towards a JSON API for<br>
          > the JDK.<br>
          > Please see the document below.<br>
          > <br>
          > -<br>
          > <br>
          > We have had the pleasure of using a clone of this API in
          some experiments we are<br>
          > conducting with<br>
          > ONNX and code reflection [1]. Using the API we were able
          to quickly write code<br>
          > to ingest and convert<br>
          > a JSON document representing ONNX operation schema into
          instances of records<br>
          > modeling the schema<br>
          > (see here [2]).<br>
          > <br>
          > The overall out-of-box experience with such a minimal
          "batteries included” API<br>
          > has so far been positive.<br>
          > <br>
          > Thanks,<br>
          > Paul.<br>
          > <br>
          > [1] <a href="https://openjdk.org/projects/babylon/"
            rel="noreferrer" target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://openjdk.org/projects/babylon/</a><br>
          > [2]<br>
          > <a
href="https://github.com/openjdk/babylon/blob/code-reflection/cr-examples/onnx/opgen/src/main/java/oracle/code/onnx/opgen/OpSchemaParser.java#L87"
            rel="noreferrer" target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://github.com/openjdk/babylon/blob/code-reflection/cr-examples/onnx/opgen/src/main/java/oracle/code/onnx/opgen/OpSchemaParser.java#L87</a><br>
          > <br>
          > # Towards a JSON API for the JDK<br>
          > <br>
          > One of the most common requests for the JDK is an API for
          parsing and generating<br>
          > JSON. While JSON originated as a text-based serialization
          format for JSON<br>
          > objects ("JSON" stands for "JavaScript Object Notation"),
          because of its simple<br>
          > and flexible syntax, it eventually found use outside the
          JavaScript ecosystem as<br>
          > a general data interchange format, such as framework
          configuration files and web<br>
          > service requests/response formats.<br>
          > <br>
          > While the JDK cannot, and should not, provide libraries
          for every conceivable<br>
          > file format or protocol, the JDK philosophy is one of
          "batteries included",<br>
          > which is to say we should be able to write basic programs
          that use common<br>
          > protocols such as HTTP, without having to appeal to third
          party libraries.<br>
          > The Java ecosystem already has plenty of JSON libraries,
          so inclusion in<br>
          > the JDK is largely meant to be a convenience, rather than
          needing to be the "one<br>
          > true" JSON library to meet the needs of all users. Users
          with specific needs<br>
          > are always free to select one of the existing third-party
          libraries.<br>
          > <br>
          > ## Goals and requirements<br>
          > <br>
          > Our primary goal is that the library be simple to use for
          parsing, traversing,<br>
          > and generating conformant JSON documents. Advanced
          features, such as data<br>
          > binding or path-based traversal should be possible to
          implement as layered<br>
          > features, but for simplicity are not included in the core
          API. We adopt a goal<br>
          > that the performance should be "good enough", but where
          performance<br>
          > considerations conflict with simplicity and usability, we
          will choose in favor<br>
          > of the latter.<br>
          > <br>
          > ## API design approach<br>
          > <br>
          > The description of JSON at `https:://<a
            href="http://json.org" rel="noreferrer" target="_blank"
            moz-do-not-send="true">json.org</a>` describes a JSON
          document using<br>
          > the familiar "railroad diagram":<br>
          > ![image](<a href="https://www.json.org/img/value.png"
            rel="noreferrer" target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://www.json.org/img/value.png</a>)<br>
          > <br>
          > This diagram describes an algebraic data type (a sum of
          products), which we<br>
          > model directly with a set of Java interfaces:<br>
          > <br>
          > ```<br>
          > interface JsonValue { }<br>
          > interface JsonArray extends JsonValue {
          List<JsonValue> values(); }<br>
          > interface JsonObject extends JsonValue { Map<String,
          JsonValue> members(); }<br>
          > interface JsonNumber extends JsonValue { Number
          toNumber(); }<br>
          > interface JsonString extends JsonValue { String value();
          }<br>
          > interface JsonBoolean extends JsonValue  { boolean
          value(); }<br>
          > interface JsonNull extends JsonValue { }<br>
          > ```<br>
          > <br>
          > These interfaces have (hidden) companion implementation
          classes that admit<br>
          > greater flexibility of implementation than modeling them
          directly with records<br>
          > would permit.<br>
          > Further, these interfaces are unsealed. We compromise on
          the sealed sum of<br>
          > products to enable<br>
          > alternative implementations, for example to support
          alternative formats that<br>
          > encode the same information in a JSON document but in a
          more efficient form than<br>
          > text.<br>
          > <br>
          > The API has static methods for parsing strings into a
          `JsonValue`, conversion to<br>
          > and from purely untyped representations (lists and maps),
          and factory methods<br>
          > for building JSON documents. We apply composition
          consistently, e.g, a<br>
          > JsonString has a string, a JsonObject has a map of string
          to JsonValue, as<br>
          > opposed to extension for structural JSON values.<br>
          > <br>
          > It turns out that this simple API is almost all we need
          for traversal. It gives<br>
          > us an immutable representation of a document, and we can
          use pattern matching to<br>
          > answer the myriad questions that will come up (Does this
          object have key X? Does<br>
          > it map to a number? Is that number representable as an
          integer?) when going<br>
          > from an untyped format like JSON to a more strongly typed
          domain model.<br>
          > Given a simple document like:<br>
          > <br>
          > ```<br>
          >    {<br>
          >        "name": "John”,<br>
          >        "age": 30<br>
          >    }<br>
          > ```<br>
          > <br>
          > we can parse and traverse the document as follows:<br>
          > <br>
          > ```<br>
          > JsonValue doc = Json.parse(inputString);<br>
          > if (doc instanceof JsonObject o<br>
          >    && o.members().get("name") instanceof
          JsonString s<br>
          >    && s.value() instanceof String name<br>
          >    && o.members().get("age") instanceof
          JsonNumber n<br>
          >    && n.toNumber() instanceof Long l && l
          instanceof int age) {<br>
          >            // use "name" and "age"<br>
          >        }<br>
          > ```<br>
          > <br>
          > Later, when the language acquires the ability to expose
          deconstruction patterns<br>
          > for arbitrary interfaces (similar to today's record
          patterns, see<br>
          > <a
href="https://openjdk.org/projects/amber/design-notes/patterns/towards-member-patterns"
            rel="noreferrer" target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://openjdk.org/projects/amber/design-notes/patterns/towards-member-patterns</a>),<br>
          > this will be simplifiable to:<br>
          > <br>
          > ```<br>
          > JsonValue doc = Json.parse(inputString);<br>
          > if (doc instanceof JsonObject(var members)<br>
          >    && members.get("name") instanceof
          JsonString(String name)<br>
          >    && members.get("age") instanceof
          JsonNumber(int age)) {<br>
          >            // use "name" and "age"<br>
          >        }<br>
          > ```<br>
          > <br>
          > So, overtime, as more pattern matching features are
          introduced we anticipate<br>
          > improved use of the API. This is a primary reason why the
          API is so minimal.<br>
          > Convenience methods we add today, such as a method that
          accesses a JSON<br>
          > object component as say a JSON string or throws an
          exception, will become<br>
          > redundant in the future.<br>
          > <br>
          > ## JSON numbers<br>
          > <br>
          > The specification of JSON number makes no explicit
          distinction between integral<br>
          > and decimal numbers, nor specifies limits on the size of
          those numbers.<br>
          > This is a common source of interoperability issues when
          consuming JSON<br>
          > documents. Generally users cannot always but often do
          assume JSON numbers are<br>
          > parsable, without loss of precision, to IEEE
          double-precision floating point<br>
          > numbers or 32-bit signed integers.<br>
          > <br>
          > In this respect the API provides three means to operate
          on the JSON number,<br>
          > giving the user full control:<br>
          > <br>
          > 1. Underlying string representation can be obtained, if
          preserving syntactic<br>
          >   details such as leading or trailing zeros is important.<br>
          > 2. The string representation can be parsed to an instance
          of `BigDecimal`, using<br>
          >   `toBigDecimal` if preserving decimal numbers is
          important.<br>
          > 3. The string representation can be parsed into an
          instance of `Long`, `Double`,<br>
          >   `BigInteger`, or `BigDecimal`, using `toNumber`. The
          result of this method<br>
          >   depends on how the representation can be parsed,
          possibly losing precision,<br>
          >   choosing a suitably convenient numeric type that can
          then be pattern<br>
          >   matched on.<br>
          > <br>
          > Primitive pattern matching will help as will further
          pattern matching features<br>
          > enabling the user to partially match.<br>
          > <br>
          > ## Prototype implementation<br>
          > <br>
          > The prototype implementation is currently located into
          the JDK sandbox<br>
          > repository<br>
          > under the `json` branch, see<br>
          > here<br>
          > <a
href="https://github.com/openjdk/jdk-sandbox/tree/json/src/java.base/share/classes/java/util/json"
            rel="noreferrer" target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://github.com/openjdk/jdk-sandbox/tree/json/src/java.base/share/classes/java/util/json</a><br>
          > The prototype API javadoc generated from the repository
          is also available at<br>
          > <a
href="https://cr.openjdk.org/~naoto/json/javadoc/api/java.base/java/util/json/package-summary.html"
            rel="noreferrer" target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://cr.openjdk.org/~naoto/json/javadoc/api/java.base/java/util/json/package-summary.html</a><br>
          > <br>
          > ### Testing and conformance<br>
          > <br>
          > The prototype implementation passes all conformance test
          cases but two,<br>
          > available<br>
          > on <a href="https://github.com/nst/JSONTestSuite"
            rel="noreferrer" target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://github.com/nst/JSONTestSuite</a>.
          The two exceptions are the ones which<br>
          > the<br>
          > prototype specifically prohibits, i.e, duplicated names
          in JSON objects<br>
          > (<a
href="https://cr.openjdk.org/~naoto/json/conformance/results/parsing.html#35"
            rel="noreferrer" target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://cr.openjdk.org/~naoto/json/conformance/results/parsing.html#35</a>).<br>
          > <br>
          > ### Performance<br>
          > <br>
          > Our main focus so far has been on the API design and a
          functional<br>
          > implementation.<br>
          > Hence, there has been less focus on performance even
          though we know there are a<br>
          > number of performance enhancements we can make
          eventually.<br>
          > We are reasonably happy with the current performance. The<br>
          > implementation performs well when compared to other JSON
          implementations<br>
          > parsing from string instances and traversing documents.<br>
          > <br>
          > An example of where we may choose simplicity and
          usability over performance<br>
          > is the rejection of JSON documents containing objects
          that in turn contain<br>
          > members<br>
          > with duplicate names. That may increase the cost of
          parsing, but simplifies the<br>
          > user<br>
          > experience for the majority of cases since if we
          reasonably assume JsonObjects<br>
          > are<br>
          > map-like, what should the user do with such members, pick
          one the last one?<br>
          > merge<br>
          > the values? or reject?<br>
          > <br>
          > ## A JSON JEP?<br>
          > <br>
          > We plan to draft JEP when we are ready. Attentive readers
          will observe that<br>
          > a JEP already exists, JEP 198: Light-Weight JSON API<br>
          > (<a href="https://openjdk.org/jeps/198" rel="noreferrer"
            target="_blank" moz-do-not-send="true"
            class="moz-txt-link-freetext">https://openjdk.org/jeps/198</a>).
          We will<br>
          > either update this JEP, or withdraw it and draft a new
          one.<br>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>