A JSON5 Library for Java (11+)
The JSON5 Standard tries to make JSON more human-readable
This is a reference implementation, capable of parsing JSON5 data according to the specification.
In order to use the code, you can either download the jar, or use the Maven dependency:
Note: Starting with version 2.0.0, the Maven dependency is now also available from Maven Central.
<!-- Repository -->
<repository>
<id>syntaxerror.at</id>
<url>https://maven.syntaxerror.at</url>
</repository>
<!-- Dependency -->
<dependency>
<groupId>at.syntaxerror</groupId>
<artifactId>json5</artifactId>
<version>2.0.0</version>
</dependency>
The library itself is located in the module json5
.
To parse a JSON object ({ ... }
), all you need to do is:
import at.syntaxerror.json5.JSONObject;
//...
JSONObject jsonObject = new JSONObject("{ ... }");
Or if you want to read directly from a Reader
or InputStream
:
import java.io.InputStream;
import at.syntaxerror.json5.JSONObject;
//...
try(InputStream stream = ...) {
JSONObject jsonObject = new JSONObject(new JSONParser(stream));
//...
} catch (Exception e) {
//...
}
Just replace JSONObject
with JSONArray
to read list-like data ([ ... ]
).
Both the JSONObject
and JSONArray
class contain two methods for serialization:
toString()
andtoString(int indentFactor)
The normal toString()
method will return the compact string representation, without any optional whitespaces.
The indentFactor
of the toString(int indentFactor)
method will enable pretty-printing if > 0
.
Any value < 1
will disable pretty-printing. The indent factor indicates the number of spaces before each key-value pair/ value:
indentFactor = 2
{
"key0": "value0",
"key1": {
"nested": 123
},
"key2": false
}
[
"value",
{
"nested": 123
},
false
]
indentFactor = 0
{"key0":"value0","key1":{"nested":123},"key2":false}
["value",{"nested":123},false]
Calling json.toString(indentFactor)
is the same as JSONStringify.toString(json, indentFactor)
.
The getXXX
methods are used to read values from the JSON object/ array.
The set
methods are used to override or set values in the JSON object/ array.
The add
and insert
methods are used to add values to a JSON array.
Supported data types are:
boolean
byte
short
int
float
double
Number
(any sub-class)String
JSONObject
JSONArray
Instants
(since1.1.0
, see below)
The normal getXXX(String key)
and getXXX(int index)
methods will throw an exception if the specified key or index does not exist, but the
getXXX(String key, XXX defaults)
and getXXX(int index, XXX defaults)
methods will return the default value (parameter defaults
) instead.
The set(int index, Object value)
method will also throw an exception if the index does not exist. You can use add(Object value)
instead to append a value to the list.
The getter-methods for numbers always return a rounded or truncated result.
If the actual number is too large to fit into the requested type, the upper bits are truncated (e.g. int
to byte
truncates the upper 24 bits).
If the actual number is a decimal number (e.g. 123.456
), and the requested type is not (e.g. long
), the decimal places are discarded.
To check if a number can fit into a type, you can use the getXXXExact
methods, which will throw an exception if the conversion is not possible without altering the result.
Numbers are internally always stored as either a java.math.BigInteger
, java.math.BigDecimal
, or double
(double
is used for Infinity
and NaN
only). Therefore, any method
returning raw java.lang.Object
s will return numbers as one of those types. The same behaviour applies to the getNumber
methods.
Instants (date and time) are now supported. This option can be toggled via the options listed below.
The JSONOptions
class allows you to customize the behaviour of the parser and stringifyer. It can be created via the builder subclass.
You can also set the default options used if the supplied options are null
, by using the method setDefaultOptions(JSONOptions)
. The default options must not be null
.
The following options are currently implemented:
parseInstants
: (defaulttrue
, Parser-only) (proposed here)
Whether instants should be parsed as such.
If this isfalse
,parseStringInstants
andparseUnixInstants
are ignoredparseStringInstants
: (defaulttrue
, Parser-only) (proposed here)
Whether string instants (according to RFC 3339, Section 5.6) should be parsed as such.
Ignored ifparseInstants
isfalse
parseUnixInstants
: (defaulttrue
, Parser-only) (proposed here)
Whether unix instants (integers) should be parsed as such.
Ignored ifparseInstants
isfalse
stringifyUnixInstants
: (defaultfalse
, Stringify-only) (proposed here)
Whether instants should be stringifyed as unix timestamps (integers).
If this isfalse
, instants will be stringifyed as strings (according to RFC 3339, Section 5.6)allowNaN
: (defaulttrue
, Parser-only) (proposed here)
WhetherNaN
should be allowed as a numberallowInfinity
: (defaulttrue
, Parser-only) (proposed here)
WhetherInfinity
should be allowed as a number. This applies to both+Infinity
and-Infinity
allowInvalidSurrogates
: (defaulttrue
, Parser-only) (proposed here)
Whether invalid unicode surrogate pairs should be allowedquoteSingle
: (defaultfalse
, Stringify-only)
Whether strings should be single-quoted ('
) instead of double-quoted ("
). This also includes a JSONObject's member names
- added
clear()
method:
removes all values from an object/array - added
remove(String key)
andremove(int index)
methods:
remove a certain key/index from an object/array
- fixed a bug where stringifying non-printable unicode characters would throw a ClassCastException
- fixed a bug where checking for invalid unicode surrogate pairs would not work as intended
- added option
duplicateBehavior
(Parser-only) for different duplicate behaviors toJSONOptions
(proposed here). The default behavior isUNIQUE
. The enumJSONOptions.DuplicateBehavior
defines the following behaviors:UNIQUE
: Throws an exception when a key is encountered multiple times within the same objectLAST_WINS
: Only the last encountered value is significant, all previous occurrences are silently discardedDUPLICATE
: Wraps duplicate values inside an array, effectively treating them as if they were declared as one
Example:
{
"a": true,
"a": 123
}
UNIQUE
throws a JSONException
, LAST_WINS
declares a
as 123
.
When the behavior is DUPLICATE
, the snippet above is effectively equal to the following:
{
"a": [
true,
123
]
}
- the
JSONParser
no longer uses regular expressions for parsing - removed options
parseInstants
,parseStringInstants
andparseUnixInstants
fromJSONOptions
.- you can still use
getInstant(...)
inJSONObject
andJSONArray
, but the instant will now be parsed dynamically rather than when the full JSON is parsed. - furthermore, you can still add
Instant
s toJSONObject
s andJSONArray
s and use thestringifyUnixInstants
option
- you can still use
- added options to
JSONOptions
:allowBinaryLiterals
: (defaultfalse
, Parser-only)
Allows the use of binary literals (prefixed with0b
or0B
) for integersallowOctalLiterals
: (defaultfalse
, Parser-only) Allows the use of octal literals (prefixed with0o
or0O
) for integersallowHexFloatingLiterals
: (defaultfalse
, Parser-only)
Allows the use of hexadecimal floating-point notationi (e.g.0xA.BCp+12
) for floating-point numbersallowJavaDigitSeparators
: (defaultfalse
, Parser-only)
Allows the use of Java's_
digit separators (e.g.123_456
for123456
) for integers and floating-point numbers.allowCDigitSeparators
: (defaultfalse
, Parser-only)
Allows the use of C23's'
digit separators (e.g.123'456
for123456
) for integers and floating-point numbers.allowLongUnicodeEscapes
: (defaultfalse
, Parser-only)
Allows the use of 32-bit unicode escape sequences (e.g.\U0001F642
for🙂
)stringifyAscii
: (defaultfalse
, Stringify-only)
Ensures that the stringifyed JSON is always valid ASCII by replacing non-ASCII characters with their UTF-16 unicode escape sequence.
- added methods to create shallow (
copy
) and deep copies (deepCopy
) ofJSONObject
s andJSONArray
s - added an additional
forEach
method toJSONObject
, which takes aBiConsumer<String, Object>
rather than aConsumer<Map.Entry<String, Object>>
- added an additional
forEach
method toJSONArray
, which takes aBiConsumer<Integer, Object>
rather than aConsumer<Object>
- added
removeIf
methods toJSONObject
andJSONArray
, which take aBiPredicate<String, Object>
orBiPredicate<Integer, Object>
and remove all the entries where the predicate returnstrue
. - added
retainIf
methods toJSONObject
andJSONArray
, which take aBiPredicate<String, Object>
orBiPredicate<Integer, Object>
and retain only the entries where the predicate returnstrue
. - added
removeIf(String, Predicate<Object>)
andremoveXIf(String, Predicate<X>)
methods toJSONObject
, which removes the value associated with the given key if the predicate returnstrue
. - added
retainIf(String, Predicate<Object>)
andretainXIf(String, Predicate<X>)
methods toJSONObject
, which retains the value associated with the given key only if the predicate returnstrue
. - added
removeKeys(JSONObject)
method toJSONObject
, which removes every key that also exists in the givenJSONObject
- added
retainKeys(JSONObject)
method toJSONObject
, which retains only the keys that also exist in the givenJSONObject
- added
putAll(JSONObject)
method toJSONObject
, which copies (shallow copy) all values of the givenJSONObject
to the target object - added
putAllDeep(JSONObject)
method toJSONObject
, which copies (deep copy) all values of the givenJSONObject
to the target object - added
setIfAbsent(String, Object)
andsetIfPresent(String, Object)
methods toJSONObject
, which sets the value only if the key is either absent or present, respectively. - added
compute
,computeX
,computeIfAbsent
,computeXIfAbsent
,computeIfPresent
,computeXIfPresent
methods toJSONObject
, which sets the value returned by the (re)mapping function either unconditionally, if the key is absent, or if the key is present, respectively. - added
sublist
anddeepSublist
methods toJSONArray
, which copies (shallow or deep copy, respectively) part of theJSONArray
to a newJSONArray
. - added
removeAll
andretainAll
methods toJSONArray
, which remove all or retain only common values of theJSONArray
s. - added
addAll(JSONArray)
method toJSONArray
, which copies (shallow copy) all values of the givenJSONArray
to the target array. - added
addAllDeep(JSONArray)
method toJSONArray
, which copies (deep copy) all values of the givenJSONArray
to the target array.
Note regarding digit separators: Digit separators may neither occur next to each other, nor at the beginning nor the end of a literal. They can also be used within binary/octal/hexadecimal and hexadecimal floating-point literals.
The JavaDoc for the latest version can be found here.
This project is partly based on stleary's JSON-Java library.
This project is licensed under the MIT License