JEP 540: Simple JSON API (Incubator)

8344154

Summary

Define a simple, standard API for parsing and generating JSON documents

so that doing so does not require an external library. Enable many JSON

processing tasks to be accomplished with little coding. This is an

incubating API.

incubating API

History

This JEP supersedes JEP 198,

Light-Weight JSON API, which was written in 2014. Circumstances have

changed in the intervening years, so here we take a different approach.

JEP 198

Goals

Provide a standard means in the Java Platform to process

RFC 8259 compliant JSON documents with low ceremony.

RFC 8259

Keep the API small, simple, and easy to learn. Provide only those data

types and operations required for strict conformance to RFC 8259,

in order to facilitate machine-to-machine communication. Avoid

features such as multiple parsing configurations, syntax extensions,

data binding, and streaming.

Keep the API small, simple, and easy to learn. Provide only those data

types and operations required for strict conformance to RFC 8259,

in order to facilitate machine-to-machine communication. Avoid

features such as multiple parsing configurations, syntax extensions,

data binding, and streaming.

Ensure that code that navigates and extracts data from JSON documents

with a known structure is simple and readable. Because JSON documents

do not have schemas, such code serves as a de facto schema and

should be readable as such.

Ensure that code that navigates and extracts data from JSON documents

with a known structure is simple and readable. Because JSON documents

do not have schemas, such code serves as a de facto schema and

should be readable as such.

Enable easy and quick exploration of unfamiliar JSON documents. We

often interact with JSON documents in an exploratory manner, writing

code not using a specification but instead trying it out against

example documents. The API should provide methods that fail fast with

clear error messages, enabling quick exploration.

Enable easy and quick exploration of unfamiliar JSON documents. We

often interact with JSON documents in an exploratory manner, writing

code not using a specification but instead trying it out against

example documents. The API should provide methods that fail fast with

clear error messages, enabling quick exploration.

Ensure that missing or unexpected values can be handled in a resilient

fashion, since JSON document structures can evolve over time.

Ensure that missing or unexpected values can be handled in a resilient

fashion, since JSON document structures can evolve over time.

Make the JDK itself capable of parsing and generating JSON documents.

Make the JDK itself capable of parsing and generating JSON documents.

Non-Goals

It is not a goal to create an API that supplants established external

JSON libraries.

Motivation

JSON is ubiquitous in modern computing. The Java ecosystem contains a

wide range of established JSON libraries:

Jackson,

Gson, Jakarta JSON

Processing and

Binding,

Fastjson 2, and more. Not

only do these libraries enable the parsing and generation of JSON

documents, but they also support extended JSON syntaxes such as

JSON5 and include higher-level features such as

data binding, i.e., converting Java objects to and from JSON with a high

degree of customization, and event-based streaming.

Jackson

Gson

Processing

Binding

Fastjson 2

JSON5

We often, however, just need to perform simple tasks such as extracting

some data from a JSON document. The Python or Go code to accomplish such

tasks is simple; the Java code should be equally simple.

For example, consider the task of computing the average of a set of

forecast temperatures in a response from the U.S. National Weather

Service REST API. The response is a JSON document that looks like this:

[U.S. National Weather

Service REST API](https://www.weather.gov/documentation/services-web-api)

To compute the average forecast temperature requires parsing the

document, navigating to the location in the structure that contains the

forecasts, and iterating over the array of forecasts while extracting

the temperature data. We should be able to tackle simple tasks like this

with simple Java code, without installing an external library and

without suspecting that another language might make us more productive.

A key goal driving the recent evolution of the Java Platform has been to

enable simple tasks to be accomplished more easily and with less

ceremony. Features serving this goal include convenience factory

methods for collections, var

declarations, running programs from

source files, and compact source files

and instance main methods. A simple JSON

API for parsing and generating JSON documents would also serve this

important goal.

[convenience factory

methods for collections](https://openjdk.org/jeps/269)

[var

declarations](https://openjdk.org/jeps/286)

[running programs from

source files](https://openjdk.org/jeps/330)

[compact source files

and instance main methods](https://openjdk.org/jeps/512)

Using JSON in the JDK

A standard JSON API in the Java Platform would also pave the way for

further use of JSON in the Platform and by the JDK itself, since the JDK

cannot have external dependencies. One potential use case is

configuration files. The JDK uses the property

file

format for various configuration files, such as security properties

files.

A weakness of this format is that it cannot express structured data. To

represent an array in a property file, you must use clumsy workarounds

such as sequentially numbered properties:

[property

file](https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/util/Properties.html)

[security properties

files](https://docs.oracle.com/en/java/javase/26/security/security-properties-file.html)

With JSON built into the JDK, configuration files could represent arrays

naturally, using JSON arrays:

Description

The

jdk.incubator.json

API is organized around the

JsonValue

interface, which represents a JSON value.

jdk.incubator.json

JsonValue

The JSON syntax has four kinds of primitives:

JSON strings, delimited with double quotes:

"Hello"

"My name is 'Bob'"

"\u006a\u0061\u0076\u0061"

JSON strings, delimited with double quotes:

JSON numbers, represented in base 10 using decimal digits:

6 6.0 31.84 2.9E+5

JSON numbers, represented in base 10 using decimal digits:

JSON boolean literals: true and false

JSON boolean literals: true and false

The JSON null literal: null

The JSON null literal: null

and two kinds of structures:

JSON objects, delimited by { } and composed of comma-separated

members. A member has a name, also called a key, and a value,

separated by a colon:

{

"address" : "123 Smith Street",

"value" : 31.84,

"coordinates" : [ [ 37, 23, 41 ], [ -121, 57, 10 ] ]

}

JSON objects, delimited by { } and composed of comma-separated

members. A member has a name, also called a key, and a value,

separated by a colon:

JSON arrays, delimited by [ ] and composed of comma-separated

JSON values:

[ 1, 2, 3, { "value": "4" }, [ 5, 6 ] ]

JSON arrays, delimited by [ ] and composed of comma-separated

JSON values:

The JsonValue interface thus has six corresponding sub-interfaces:

JsonString,

JsonNumber,

JsonBoolean,

JsonNull,

JsonObject,

and

JsonArray.

Each interface declares operations appropriate to its corresponding JSON

syntactic element: Instances of the primitive sub-interfaces offer

conversions to Java primitives and strings, JsonObject instances

expose members, and JsonArray instances expose array elements.

JsonString

JsonNumber

JsonBoolean

JsonNull

JsonObject

JsonArray

The JsonValue interface is sealed,

which guarantees that any JsonValue instance is always one of this

fixed set of subtypes and thus exhaustive switch expressions and

statements do not require a default clause.

sealed

The JSON API makes it easy to parse JSON documents that conform to

RFC 8259. The

parse

method of the

Json

class returns a tree of JsonValue instances that expose the names,

types, and values of the parsed JSON data. Returning to the National

Weather Service example, we can compute the average forecast temperature

in just a few lines:

RFC 8259

parse)

Json

(The complete example is shown in the Appendix.)

Appendix

The API also makes it easy to generate JSON documents. For example, this

code:

produces the output:

Parsing and navigating JSON documents

The Json class can parse a JSON document contained in either a

String or a char array. A JSON document might be a REST API response

body read from the network, a configuration file read from disk, or some

other text payload produced by an application.

Parsing a JSON document requires a single call to one of the

Json.parse

methods:

Json.parse)

Parsing is strict: The document must conform to RFC 8259. Syntax

extensions such as trailing commas and comments are not supported.

Additionally, documents must not have objects with duplicate member

names. This policy, permitted by the RFC, provides maximum

interoperability and predictability, and reduces concerns about

processing malformed or ambiguous JSON documents. (See

below for a full discussion.)

RFC 8259

below

Successful parsing returns an instance of JsonValue. Unsuccessful

parsing throws an unchecked

JsonParseException.

The exception includes a detail message that provides specific

information about the error and its location in the document. For

example, the exception thrown when a document has duplicate member names

in an object has the form:

JsonParseException

Most JSON documents have a JSON object or JSON array at the root. For

example, a JSON-formatted thread dump produced by the jcmd

tool

contains a root object:

[JSON-formatted thread dump produced by the jcmd

tool](https://download.java.net/java/early_access/jdk27/docs/api/jdk.management/com/sun/management/doc-files/threadDump.html)

The root object contains a single member, the nested threadDump

object, and threadDump itself contains both primitive and structural

JSON values.

Once you have obtained the root JsonValue via Json.parse(...), you

can retrieve values from objects and arrays via their access methods,

which return the requested member value or array element as a

JsonValue.

get(String)

obtains the value of an object member. To obtain the

thread dump object:

JsonValue threadDump = root.get("threadDump");

get(String)

obtains the value of an object member. To obtain the

thread dump object:

get(String))

get(int)

obtains an array element. To obtain the root thread container:

JsonValue firstContainer = threadDump.get("threadContainers").get(0);

get(int)

obtains an array element. To obtain the root thread container:

get(int))

If the JsonValue instance is of the wrong type, or if the requested

member or element does not exist, the access methods throw a

JsonValueException.

JsonValueException

Converting JSON values to Java values

You can convert a JSON value to a Java value by calling one of the

conversion methods of the JsonValue interface. For a conversion to

succeed, the JsonValue must be an instance of the appropriate subtype

of JsonValue:

JsonString

asString())

JsonNumber

asInt())

JsonNumber

asLong())

JsonNumber

asDouble())

JsonBoolean

asBoolean())

JsonObject

asMap())

JsonArray

asList())

For example, you can retrieve the Java String value associated with

the thread dump's "time" member:

You can convert the thread containers array into a List of JsonValue

instances and process each instance:

You can access the thread dump object as a Map to retrieve the number

of members:

You can navigate deeply into a JSON document, chaining access methods

and converting to a Java value only at the end. To retrieve the thread

identifier value of the first thread in the root thread container:

The design of the conversion methods eliminates most instanceof

checking and downcasting in cases where a specific JSON data type is

expected in a document:

asString()

converts a JsonString instance into a Java String with RFC 8259

JSON escape sequences translated to their corresponding characters.

asString()

converts a JsonString instance into a Java String with RFC 8259

JSON escape sequences translated to their corresponding characters.

asString())

asInt()

converts a JsonNumber instance to a Java int if its numeric value

can be represented exactly.

asInt()

converts a JsonNumber instance to a Java int if its numeric value

can be represented exactly.

asInt())

asLong()

converts a JsonNumber instance to a Java long if its numeric value

can be represented exactly.

asLong()

converts a JsonNumber instance to a Java long if its numeric value

can be represented exactly.

asLong())

asDouble()

converts a JsonNumber instance to a Java double if its numeric

value can be represented accurately.

asDouble()

converts a JsonNumber instance to a Java double if its numeric

value can be represented accurately.

asDouble())

asBoolean()

converts a JsonBoolean instance to a Java boolean value of true

or false.

asBoolean()

converts a JsonBoolean instance to a Java boolean value of true

or false.

asBoolean())

asMap()

converts a JsonObject instance into an unmodifiable Java Map. If

the JSON object contains no members, an empty Map is returned.

asMap()

converts a JsonObject instance into an unmodifiable Java Map. If

the JSON object contains no members, an empty Map is returned.

asMap())

asList()

converts a JsonArray instance into an unmodifiable Java List. If

the JSON array contains no elements, an empty List is returned.

asList()

converts a JsonArray instance into an unmodifiable Java List. If

the JSON array contains no elements, an empty List is returned.

asList())

There is no conversion method for the JSON null value.

JsonNull

instances can be handled by testing for instanceof JsonNull or via the

tryValue method.

JsonNull

tryValue

If a JsonValue is not an instance of the appropriate subtype for a

conversion method then the method throws a JsonValueException. For

example, calling asInt() on a JsonValue that is an instance of

JsonString will always throw this exception. No attempt is made to

parse the string value into a number.

Numeric conversions can fail for reasons such as the numeric value not

being representable in the target Java numeric type, which also causes a

JsonValueException to be thrown. See below for a

deeper discussion of number handling and conversions.

below

Handling JSON document evolution

JSON documents from a particular source may evolve, over time, in ways

that violate your previous expectations of their structure and content:

You might call access methods expecting member names or array indices

that do not exist in the JSON objects and JSON arrays of the document.

You might call access methods expecting member names or array indices

that do not exist in the JSON objects and JSON arrays of the document.

You might call conversion methods applicable to one JSON type on

values of a different type.

You might call conversion methods applicable to one JSON type on

values of a different type.

If you call access or conversion methods on the wrong type, they throw a

JsonValueException. This exception is unchecked, so that scripts and

small programs are easier to read and write.

Continuing with the thread dump example, recall that the root JSON value

is a JSON object with a single member, threadDump. This code:

throws a JsonValueException because the JSON object does not contain a

member with the name "threadName", while this code:

throws a JsonValueException because the threadDump member is a JSON

object, not a JSON array.

The exception message describes the path leading from the root of the

JSON document to the unexpected JSON value, as well as the position in

the JSON document. This is helpful when a chain of access methods

navigates deeply into the document. For example, if the earlier code

snippet to extract the thread identifier incorrectly converted it to a

boolean instead of a long:

then the exception thrown by asBoolean() would have the form:

Handling optional members

If you do not know whether a JSON object has a member with a given name,

you can use the

tryGet

access method. This returns an Optional instance containing the

member's value, or else an empty Optional if the member does not

exist. (The get method, by contrast, confirms that the member exists

and throws an exception if it does not.) The tryGet method throws a

JsonValueException if it is not called on a JsonObject.

tryGet)

Consider the following thread object:

A thread object contains multiple optional members. One of them is the

waitingOn member, which contains the JSON string representation of the

object on which the thread is waiting. However, in cases where the

thread is not waiting, the thread object may look like this:

Thus, when processing thread objects from a thread dump, you must be

prepared for the waitingOn member to be absent. You can handle this

via tryGet:

The lambda passed to ifPresent is called only if the waitingOn

member is present.

Handling null values

If you do not know whether a JSON value is a JSON null, you can use the

tryValue

access method. This method returns an empty Optional if the JSON value

upon which it is invoked is a JsonNull; otherwise, it returns that

value.

tryValue)

For example, a thread container object typically looks like this:

Here, the parent member's value is a JSON string, the parent

container's name. However, the container named "<root>" is the root of

all containers and looks like this:

The root container has no parent, so the parent member's value is a

JSON null. Thus, when processing container objects from a thread dump,

you must be prepared for the parent member to be either a JSON string or

a JSON null. You can handle this via tryValue:

The lambda passed to ifPresent is called only if the "parent" member's

value is not a JSON null.

Handling variable structure and content

The structure and content of JSON documents in a particular context is

often uniform, but sometimes it is variable. It might vary across

different sources, or over time from a particular source which itself

evolves, or even within the same document.

For example, in thread dumps in JDK 26 and earlier releases, thread

identifiers are represented as JSON strings; in JDK 27 and later

releases, thread

identifiers are represented as JSON numbers.

[JDK 27 and later

releases](https://bugs.openjdk.org/browse/JDK-8381002)

Code that expects the tid to be a JSON number, for example:

will fail with a JsonValueException if it encounters a thread dump

produced by a version of the JDK that emits tid values as JSON

strings.

In either representation, the numeric value is specified to fit in a

Java long. You could use instanceof to check whether you have a

JsonNumber or a JsonString, but it is clearer to use type patterns

in a switch statement:

Generating JSON documents

To generate a JSON document, in string form, from a JsonValue, simply

invoke its

toString

method. This method returns a compact string representation in which all

members, elements, and values are emitted on the same line, with no

whitespace between them.

toString)

For example, this code:

prints:

(The toString method is distinct from the asString method, which

throws an exception if the JsonValue upon which it is invoked is not a

JsonString.)

The static method

Json.toDisplayString

emits a pretty-printed form of a JSON document, where members and

elements are separated by newlines and nested structures are indented by

a given amount. For example, this code:

Json.toDisplayString)

prints the above structure with two spaces of indentation:

The outputs of both the toString and Json.toDisplayString methods

are parsable by the Json.parse method, which will produce a

JsonValue that is equivalent to the original.

JSON numbers

The syntax for JSON numbers defined in RFC 8259 can represent

decimal values of arbitrary precision and range. The JSON API enables

JSON numbers to be processed losslessly; in most applications, however,

common numeric types suffice.

RFC 8259

RFC 8259 advises that good interoperability among JSON libraries

can be achieved by using

IEEE 754 64-bit binary

floating point values, corresponding to the Java double type. The asDouble()

method therefore converts a numeric JSON value to a Java double. The

JSON value must lie within the range that a double can represent; if

the value is out of range, a JsonValueException is thrown. Infinity

and not-a-number ("NaN") values are not representable in JSON, and thus

are never returned. Negative zero, however, is representable in JSON,

and thus may be returned.

IEEE 754

asDouble())

If the JSON value has more precision than can be represented in a

double, the value is rounded to the closest double value. For

example:

Integral numeric values are frequently used, so the asInt()

method converts a numeric JSON value to a Java int value. The JSON

value must be exactly representable as an int, otherwise an exception

is thrown. Numbers that have a syntactic fractional part but that

represent integral values are converted; for example:

asInt())

The conversion method asLong()

is similar to asInt() except that it returns a Java long value and

supports any JSON numeric value that can be represented exactly as a

long.

asLong())

If you need a narrower primitive type than int or double, you can

use primitive types in patterns

(currently a preview feature), to perform a safe conversion. For

example, if you expect a JSON number to be representable as a short:

primitive types in patterns

As mentioned previously, JSON numbers can have arbitrary precision and

range. The asDouble(), asInt(), and asLong() methods, by

definition, handle only a subset of JSON numeric values; they reject

out-of-range values, and they round overly-precise values. To handle

JSON numeric data without loss of information, you can convert

essentially any JSON number to a

java.math.BigDecimal

instance:

java.math.BigDecimal

Alternatives

Provide a full feature set instead of a limited

feature set.

The many existing external JSON libraries provide, among them, a

broad set of features. We cannot possibly include all of these

features in the Java Platform; we must, instead, select a subset that

provides the greatest value relative to its cost.

We have excluded the commonly provided feature of data binding. This

feature is undeniably useful and convenient for many applications.

However, it would add a significant API footprint and increase

implementation and maintenance costs dramatically. Many use cases do

not require data binding, so we consider this feature not strictly

necessary. That the Jackson and Jakarta JSON libraries factor their

data binding features into separate modules is an implicit

recognition that there are use cases that do not need data binding.

A streaming API is clearly essential for certain narrow, specialized

use cases, but it induces a fair amount of application complexity for

even simple data extraction tasks. We have thus excluded this feature.

Omitting data binding and streaming leaves us with a DOM-like

approach in which JSON documents are parsed into trees of

JSON-specific objects from which data can be extracted easily. The

API is small, and it incurs correspondingly small implementation and

maintenance costs. This satisfies the needs of a significant subset

of JSON applications, from the simplest to the moderately complex.

An application might start off using the Java Platform's JSON API but

eventually grow to need features such as data binding or streaming,

necessitating a migration to a richer API in an external library. We

do not view this scenario as a failure, and it is not sufficient

justification to include high-cost features such as JSON data binding

and streaming in the Java Platform.

Provide a full feature set instead of a limited

feature set.

[Provide a full feature set instead of a limited

feature set.]()

[The many existing external JSON libraries provide, among them, a

broad set of features. We cannot possibly include all of these

features in the Java Platform; we must, instead, select a subset that

provides the greatest value relative to its cost.

We have excluded the commonly provided feature of data binding. This

feature is undeniably useful and convenient for many applications.

However, it would add a significant API footprint and increase

implementation and maintenance costs dramatically. Many use cases do

not require data binding, so we consider this feature not strictly

necessary. That the Jackson and Jakarta JSON libraries factor their

data binding features into separate modules is an implicit

recognition that there are use cases that do not need data binding.

A streaming API is clearly essential for certain narrow, specialized

use cases, but it induces a fair amount of application complexity for

even simple data extraction tasks. We have thus excluded this feature.

Omitting data binding and streaming leaves us with a DOM-like

approach in which JSON documents are parsed into trees of

JSON-specific objects from which data can be extracted easily. The

API is small, and it incurs correspondingly small implementation and

maintenance costs. This satisfies the needs of a significant subset

of JSON applications, from the simplest to the moderately complex.

An application might start off using the Java Platform's JSON API but

eventually grow to need features such as data binding or streaming,

necessitating a migration to a richer API in an external library. We

do not view this scenario as a failure, and it is not sufficient

justification to include high-cost features such as JSON data binding

and streaming in the Java Platform.]()

The many existing external JSON libraries provide, among them, a

broad set of features. We cannot possibly include all of these

features in the Java Platform; we must, instead, select a subset that

provides the greatest value relative to its cost.

We have excluded the commonly provided feature of data binding. This

feature is undeniably useful and convenient for many applications.

However, it would add a significant API footprint and increase

implementation and maintenance costs dramatically. Many use cases do

not require data binding, so we consider this feature not strictly

necessary. That the Jackson and Jakarta JSON libraries factor their

data binding features into separate modules is an implicit

recognition that there are use cases that do not need data binding.

A streaming API is clearly essential for certain narrow, specialized

use cases, but it induces a fair amount of application complexity for

even simple data extraction tasks. We have thus excluded this feature.

Omitting data binding and streaming leaves us with a DOM-like

approach in which JSON documents are parsed into trees of

JSON-specific objects from which data can be extracted easily. The

API is small, and it incurs correspondingly small implementation and

maintenance costs. This satisfies the needs of a significant subset

of JSON applications, from the simplest to the moderately complex.

An application might start off using the Java Platform's JSON API but

eventually grow to need features such as data binding or streaming,

necessitating a migration to a richer API in an external library. We

do not view this scenario as a failure, and it is not sufficient

justification to include high-cost features such as JSON data binding

and streaming in the Java Platform.

[Integrate an external JSON library.

We could integrate an external library into the Java Platform and the

JDK, as a downstream fork. This would raise difficult issues over

licensing and governance. There would be continual tension over

changes flowing in both directions, arising from different criteria

regarding specification quality, compatibility, release schedules,

and so forth. (We have experienced this tension in the past, with

various XML APIs.) It seems likely that these costs, plus the

additional maintenance burden on the JDK, would outweigh the benefit

of integrating an external library.

Do nothing, since JSON is already handled well by external

libraries.

Doing nothing would not serve the larger goal of enabling simple

tasks to be accomplished more easily and with less ceremony,

especially for simple programs and for newcomers to the Java

Platform.

Adding any external dependency to an application incurs cost and adds

risk. There are probably applications that could benefit from using

JSON but that do not, because their maintainers wish to minimize cost

and risk. Such applications would benefit from having a standard JSON

API in the Java Platform.]()

Integrate an external JSON library.

We could integrate an external library into the Java Platform and the

JDK, as a downstream fork. This would raise difficult issues over

licensing and governance. There would be continual tension over

changes flowing in both directions, arising from different criteria

regarding specification quality, compatibility, release schedules,

and so forth. (We have experienced this tension in the past, with

various XML APIs.) It seems likely that these costs, plus the

additional maintenance burden on the JDK, would outweigh the benefit

of integrating an external library.

Integrate an external JSON library.

We could integrate an external library into the Java Platform and the

JDK, as a downstream fork. This would raise difficult issues over

licensing and governance. There would be continual tension over

changes flowing in both directions, arising from different criteria

regarding specification quality, compatibility, release schedules,

and so forth. (We have experienced this tension in the past, with

various XML APIs.) It seems likely that these costs, plus the

additional maintenance burden on the JDK, would outweigh the benefit

of integrating an external library.

Do nothing, since JSON is already handled well by external

libraries.

Doing nothing would not serve the larger goal of enabling simple

tasks to be accomplished more easily and with less ceremony,

especially for simple programs and for newcomers to the Java

Platform.

Adding any external dependency to an application incurs cost and adds

risk. There are probably applications that could benefit from using

JSON but that do not, because their maintainers wish to minimize cost

and risk. Such applications would benefit from having a standard JSON

API in the Java Platform.

Do nothing, since JSON is already handled well by external

libraries.

Doing nothing would not serve the larger goal of enabling simple

tasks to be accomplished more easily and with less ceremony,

especially for simple programs and for newcomers to the Java

Platform.

Adding any external dependency to an application incurs cost and adds

risk. There are probably applications that could benefit from using

JSON but that do not, because their maintainers wish to minimize cost

and risk. Such applications would benefit from having a standard JSON

API in the Java Platform.

Allow duplicate member names within JSON

objects.

This has been a longstanding issue with JSON. Early specifications

were underdetermined with respect to the handling of duplicate

member names within a single JSON object. JSON libraries behaved

inconsistently, or else provided application-settable options to

select the policy for handling duplicate names.

Unfortunately, an object with duplicate names is fundamentally

ambiguous. When the issue of duplicate names was discussed on the

ECMAScript Discussion

List in 2013, the

concern about prohibiting duplicate names was that doing so would

invalidate existing documents. Thus, the "should be unique" wording

(instead of "must") was retained, and it has been carried over to

current specifications. In particular, RFC 8259

says:

The names within an object SHOULD be unique.

...

An object whose names are all unique is interoperable in the sense

that all software implementations receiving that object will agree

on the name-value mappings. When the names within an object are not

unique, the behavior of software that receives such an object is

unpredictable.

The unpredictability arises when the object is processed by a system

consisting of multiple, independently-developed JSON libraries. This

can lead to hard-to-diagnose errors, security vulnerabilities,

decreased interoperability, and general lack of robustness. This

phenomenon is discussed in

RFC 9413,

"Maintaining Robust Protocols".

For these reasons, we have chosen a strict approach where duplicate

names are unconditionally treated as errors. The strict approach

gives high confidence in the correctness of parsed documents. We hope

that the erroneous documents mentioned in the 2013 ECMAScript

conversation have been corrected in the intervening years, and that

the software that produced those documents has been fixed.

Allow duplicate member names within JSON

objects.

[Allow duplicate member names within JSON

objects.]()

[This has been a longstanding issue with JSON. Early specifications

were underdetermined with respect to the handling of duplicate

member names within a single JSON object. JSON libraries behaved

inconsistently, or else provided application-settable options to

select the policy for handling duplicate names.]()

This has been a longstanding issue with JSON. Early specifications

were underdetermined with respect to the handling of duplicate

member names within a single JSON object. JSON libraries behaved

inconsistently, or else provided application-settable options to

select the policy for handling duplicate names.

Unfortunately, an object with duplicate names is fundamentally

ambiguous. When the issue of duplicate names was discussed on the

ECMAScript Discussion

List in 2013, the

concern about prohibiting duplicate names was that doing so would

invalidate existing documents. Thus, the "should be unique" wording

(instead of "must") was retained, and it has been carried over to

current specifications. In particular, RFC 8259

says:

[Unfortunately, an object with duplicate names is fundamentally

ambiguous. When the issue of duplicate names was discussed on the]()

[ECMAScript Discussion

List](https://esdiscuss.org/topic/json-duplicate-keys)

[RFC 8259

says](https://www.rfc-editor.org/info/rfc8259/#section-4)

The names within an object SHOULD be unique.

...

An object whose names are all unique is interoperable in the sense

that all software implementations receiving that object will agree

on the name-value mappings. When the names within an object are not

unique, the behavior of software that receives such an object is

unpredictable.

The unpredictability arises when the object is processed by a system

consisting of multiple, independently-developed JSON libraries. This

can lead to hard-to-diagnose errors, security vulnerabilities,

decreased interoperability, and general lack of robustness. This

phenomenon is discussed in

RFC 9413,

"Maintaining Robust Protocols".

RFC 9413

For these reasons, we have chosen a strict approach where duplicate

names are unconditionally treated as errors. The strict approach

gives high confidence in the correctness of parsed documents. We hope

that the erroneous documents mentioned in the 2013 ECMAScript

conversation have been corrected in the intervening years, and that

the software that produced those documents has been fixed.

Support trailing commas, comments, or other syntax extensions.

There are several variants of JSON, e.g.,

JSON5, that support comments or trailing commas

within arrays and objects. These extensions are intended to

facilitate the hand-editing of JSON documents.

Given our focus on simplicity and machine-to-machine communication,

we do not support such extensions. Doing so would enlarge the testing

matrix, increase the possibility of interoperability errors, and

increase the overall development and maintenance burden.

A common workaround is to pre-process incoming extended-JSON

documents before parsing them. For example, single-line comments on

lines starting with '#' characters are easily removed prior to

parsing:

String jsonc = Files.readString(Path.of("file-with-comments.json"));

String json = jsonc.replaceAll("(?m)^\\s#.$", "");

JsonValue jv = Json.parse(json);

Support trailing commas, comments, or other syntax extensions.

There are several variants of JSON, e.g.,

JSON5, that support comments or trailing commas

within arrays and objects. These extensions are intended to

facilitate the hand-editing of JSON documents.

JSON5

Given our focus on simplicity and machine-to-machine communication,

we do not support such extensions. Doing so would enlarge the testing

matrix, increase the possibility of interoperability errors, and

increase the overall development and maintenance burden.

A common workaround is to pre-process incoming extended-JSON

documents before parsing them. For example, single-line comments on

lines starting with '#' characters are easily removed prior to

parsing:

Testing

We will rigorously test the JSON API to ensure that only canonical forms

of RFC 8259 JSON can be parsed and generated. This will help ensure

that using the API will not result in inconsistencies when interacting

with other JSON libraries. To accomplish this, we will not only add

comprehensive unit tests to the JDK but also leverage the

established JSON Parsing Test

Suite, which contains numerous

edge-case inputs.

[JSON Parsing Test

Suite](https://github.com/nst/JSONTestSuite)

Risks and Assumptions

We assume that input JSON documents can fit in memory, as either a

String or a char array. Given our tree-based model, if we were to

allow JSON sources such as files or network connections, issues such

as insufficient memory would be possible with large documents. This

decision aligns with our minimalist design philosophy.

We assume that input JSON documents can fit in memory, as either a

String or a char array. Given our tree-based model, if we were to

allow JSON sources such as files or network connections, issues such

as insufficient memory would be possible with large documents. This

decision aligns with our minimalist design philosophy.

A risk of this proposal is that this new API might end up being used

in applications that are already using external JSON libraries,

resulting in messiness and confusion. We believe this risk is

outweighed by the benefits.

A risk of this proposal is that this new API might end up being used

in applications that are already using external JSON libraries,

resulting in messiness and confusion. We believe this risk is

outweighed by the benefits.

During the incubation period, we will gather more information about

use cases involving generating and transforming JSON documents, in

order to evolve these areas of the API. In addition, we will continue

to consider forthcoming pattern-matching language features that might

affect the design of the API.

During the incubation period, we will gather more information about

use cases involving generating and transforming JSON documents, in

order to evolve these areas of the API. In addition, we will continue

to consider forthcoming pattern-matching language features that might

affect the design of the API.

Appendix: Weather Forecast Example

The following program issues a request to the U.S. National

Weather Service REST API for a seven-day weather forecast for Santa Clara, CA.

It receives a JSON document in the response body. The program then parses the

document, navigates into the structure, and obtains an array of forecasts.

It then extracts the temperature from each forecast, averages them, and prints

the result.

[The following program issues a request to the]()

[U.S. National

Weather Service REST API](https://www.weather.gov/documentation/services-web-api)

Enabling the incubating API

The JSON API is, at present, an incubator

module, disabled by default. To use it,

you must enable it via the command-line option --add-modules jdk.incubator.json, which adds the incubator module to the set of

modules available for resolution. To run the above example program, you

must provide this option at both compile time and run time.

[incubator

module](https://openjdk.org/jeps/11)

To run the average forecast program as a single-file source code

program, do this:

The output will be something like:

To compile the program with javac and run it with java, do this:

You can use jshell to experiment interactively with the API. As

before, you must enable the incubator module on the command line:

OpenJDK logo

Installing

Contributing

Sponsoring

Developers' Guide

Vulnerabilities

JDK GA/EA Builds

Mailing lists

Wiki

IRC

Mastodon

Bluesky

Bylaws

Census

Legal

AI

Workshop

JEP Process

GitHub

Mercurial

Git

jtreg harness

(overview

archive

Adoption

Build

Client Libraries

Compatibility &amp; Specification Review

Compiler

Conformance

Core Libraries

Governing Board

HotSpot

IDE Tooling &amp; Support

Internationalization

Members

Networking

Porters

Quality

Security

Serviceability

Vulnerability

Web

overview

archive

Amber

Babylon

Brisbane

CRaC

Code Tools

Coin

Common VM Interface

Detroit

Developers' Guide

Duke

IcedTea

JDK 8 Updates

JDK 9

JDK

26

27

28

JDK Updates

JMC

Jigsaw

Lanai

Leyden

Lilliput

Loom

Memory Model Update

Multi-Language VM

Nashorn

New I/O

OpenJFX

Panama

Port: AArch32

Port: AArch64

Port: BSD

Port: Haiku

Port: MIPS

Port: Mobile

Port: PowerPC/AIX

Port: RISC-V

Port: s390x

SCTP

Shenandoah

Skara

Sumatra

Tsan

Valhalla

Wakefield

Zero

ZGC

Oracle logo

Terms of Use

GPLv2

Privacy

Trademarks