Json-den-java
Json-den-java is a library that parses (Decodes), stringifies (ENcodes) and manipulates JSON.
Its distinctive features include
- Method
equals
checks the value equality (not the reference equality).clone
deeply copies JSON values.diff
identifies different parts of two JSON values. These and the following methods properly handle hierarchical structure of JSON values. - It provides a method
getx
which can query JSON nodes located deep in hierarchical structures with a single path. For example, you can usejson.getx("how.deep.is.your.love")
instead ofjson.get("how").get("deep").get("is").get("your").get("love")
. - It provides a method
setx
which creates parent nodes as needed, like the UNIX shell commandmkdir -p
, and then updates the JSON node at the specified path. For example,json.setx("how.deep.is.your.love", "10,000ft")
sets "10,000ft" at "how.deep.is.your.love" even when the node corresponding to 'how', 'deep', 'is' or 'your' is currently absent. - It supports binary operations
intersect
,subtract
andmerge
on JSON objects and arrays. - It supports C-style line and block comments in JSON texts. Instead of the common approach, minifying JSON texts before parsing, its parser recognizes comments so that it can preserve and report the original row and column offsets of tokens on syntax errors, which is imposible in the minifying approach.
- It preserves block comments that are indicated so; start comments you want to preserve with "/**", not just with "/*". Unlike the ordinary ones, such comments are not erased while parsing, kept in internal representation, and printed back when stringified. This feature might be useful when you use JSON for a configuration file of your app and you want to annotate who, when, why, etc of each configuration item in the file. With Json-den-java, you does not lose the annotation over times when you load, update and save some of the configuration at run-time.
For more information, download the source code, run gen-apidocs.sh
included, and see the generated API documentation.
Json-den-java is under BSD-2 license.
Examples
Following are code snippets in io.github.hyunikn.jsonden.example.Example class and their console outputs when run. You can run mvn exec:java -Dexec.mainClass=io.github.hyunikn.jsonden.example.Example
in the project root directory to get the outputs.
Sample JSON files
left.json | right.json | |
---|---|---|
/** comment preserved */
/* comment dropped */
// comment dropped too
{
/** left only */
"l": {},
/** common */
"c": 7,
/** different */
"d": true,
"o": {
"l": "left", /** this goes to c, not l */
"c": [ true, false ],
"d": 1.1,
"d2": [ false, true ]
},
"a": [
{
"l": {
"L": "L"
},
"c": {
"C": null
},
"d": {
"D": "O"
}
},
[ 1, 2, 3 ],
[ 10, 20, 30 ]
]
}
|
{
"r": [],
"c": 7,
"d": false,
"o": {
"r": "right",
"c": [ true, false ],
"d": 3.3,
"d2": [ true, false ]
},
"a": [
{
"r": {
"R": "R"
},
"c": {
"C": null
},
"d": {
"D": "X"
}
},
[ 1, 2, 3 ],
[ 30, 20, 10, 0 ],
{
"r": "R"
}
]
}
|
Parse and stringify
Code:
package io.github.hyunikn.jsonden.example;
import io.github.hyunikn.jsonden.*;
import io.github.hyunikn.jsonden.exception.*;
...
...
public class Example {
public static void main(String[] argv) throws ParseError, UnreachablePath {
String leftText = readFile("left.json");
String rightText = readFile("right.json");
// parse
JsonObj left = JsonObj.parse(leftText);
JsonObj right = JsonObj.parse(rightText);
// stringify
System.out.println("# stringify with indent size 0");
System.out.println(left.stringify(0));
System.out.println("# stringify with indent size 2");
System.out.println(left.stringify(2));
Output:
# stringify with indent size 0
/** comment preserved */{/** left only */"l":{},/** common */"c":7,/** different */"d":true,"o":{"l":"left",/** this goes to c, not l */"c":[true,false],"d":1.1,"d2":[false,true]},"a":[{"l":{"L":"L"},"c":{"C":null},"d":{"D":"O"}},[1,2,3],[10,20,30]]}
# stringify with indent size 2
/** comment preserved */
{
/** left only */
"l": {},
/** common */
"c": 7,
/** different */
"d": true,
"o": {
"l": "left",
/** this goes to c, not l */
"c": [
true,
false
],
"d": 1.1,
"d2": [
false,
true
]
},
"a": [
{
"l": {
"L": "L"
},
"c": {
"C": null
},
"d": {
"D": "O"
}
},
[
1,
2,
3
],
[
10,
20,
30
]
]
}
Diff
Code:
// diff
System.out.print("# diff");
System.out.println(Jsons.prettyPrintDiff(left.diff(right)));
Output:
# diff
l:
L: {}
R: <none>
d:
L: true
R: false
o.l:
L: "left"
R: <none>
o.d:
L: 1.1
R: 3.3
o.d2.#0:
L: false
R: true
o.d2.#1:
L: true
R: false
a.#0.l.L:
L: "L"
R: <none>
a.#0.d.D:
L: "O"
R: "X"
a.#2.#0:
L: 10
R: 30
a.#2.#2:
L: 30
R: 10
r:
L: <none>
R: []
o.r:
L: <none>
R: "right"
a.#0.r.R:
L: <none>
R: "R"
a.#2.#3:
L: <none>
R: 0
a.#3.r:
L: <none>
R: "R"
Intersect, subtract and merge
Code:
// intersect, subtract and merge
System.out.println("# intersect");
System.out.println(Jsons.intersect(left, right).stringify(StrOpt.VALUES_ONLY));
System.out.println("# subtract");
System.out.println(Jsons.subtract(left, right).stringify(StrOpt.VALUES_ONLY));
System.out.println("# merge");
System.out.println(Jsons.merge(left, right).stringify(StrOpt.VALUES_ONLY));
Output:
# intersect
{
"c": 7,
"o": {
"c": [
true,
false
]
},
"a": [
{
"c": {
"C": null
}
},
[
1,
2,
3
],
[
null,
20
]
]
}
# subtract
{
"l": {},
"d": true,
"o": {
"l": "left",
"d": 1.1,
"d2": [
false,
true
]
},
"a": [
{
"l": {
"L": "L"
},
"d": {
"D": "O"
}
},
null,
[
10,
null,
30
]
]
}
# merge
{
"l": {},
"c": 7,
"d": false,
"o": {
"l": "left",
"c": [
true,
false
],
"d": 3.3,
"d2": [
true,
false
],
"r": "right"
},
"a": [
{
"l": {
"L": "L"
},
"c": {
"C": null
},
"d": {
"D": "X"
},
"r": {
"R": "R"
}
},
[
1,
2,
3
],
[
30,
20,
10,
0
],
{
"r": "R"
}
],
"r": []
}
Flatten and loadFlattened
Code:
// flatten and loadFlattened
System.out.println("# flatten");
LinkedHashMap<String, Json> flattened = left.flatten();
System.out.println(Jsons.prettyPrintFlattened(flattened));
JsonObj restored = JsonObj.instance().loadFlattened(flattened);
if (left.equals(restored)) {
System.out.println("# the original and the restored are equal");
} else {
assert false;
}
Output:
# flatten
l: {}
c: 7
d: true
o.l: "left"
o.c.#0: true
o.c.#1: false
o.d: 1.1
o.d2.#0: false
o.d2.#1: true
a.#0.l.L: "L"
a.#0.c.C: null
a.#0.d.D: "O"
a.#1.#0: 1
a.#1.#1: 2
a.#1.#2: 3
a.#2.#0: 10
a.#2.#1: 20
a.#2.#2: 30
# the original and the restored are equal
Maven Configuration
You can get the latest stable version from Maven Central by adding the following dependency in your pom.xml:
<dependency>
<groupId>io.github.hyunikn</groupId>
<artifactId>jsonden</artifactId>
<version>0.9.6</version>
</dependency>