About JSON.java

JSON.java (or simply jsonjava) is yet another JSON encoder/decoder library for the Java prorgramming language. It provides a simple interface similar to the JavaScript's JSON object. Yes, it's basically just two methods for the core functionality.

While most Java JSON libraries focus on POJOs, have their own weird container classes, parser factories, or whatnot, I wanted to take a different, simple approach and just get the data to ordinary HashMaps and ArrayLists instead. (A little later I did find another Java library that does basically the same thing but forgot to bookmark it, sorry.)

Of course, I had to provide simple wrappers for generic Maps and Lists to ease the pain of having to handle plain Objects instead of more meaningful types.

I have also added a implementation of Gössner's JSONPath. Sometimes it is handy to be able to put a query string to a configuration file and this does the job nicely.

Highlights

The API could not be simpler: JSON.parse(...) and JSON.stringify(...) — JSON goes in and Lists, Maps, Strings, Numbers, Booleans, etc. come out or vice versa. And you already know what those Java objects are.

The parser can be told to be more human friendly by turning on the relaxed mode (instead of the default strict mode.) It now allows almost all JavaScript literals (without scripts obviously) with added support for true multiline strings. (There is support for line continuation, too.) You will want to use this mode for configuration files to be able to add both /* comments */ and // comments and/or forgive missing or extra commas in arrays and objects. (Note: If you write the data back to a file, all comments etc. will be lost but at least your commas will be fixed as well.)

If you need parse and cache a lot of data, you will be happy to know that JSON.java has a built-in data deduplication for strings and numbers (which are both immutable and safe for doing so.) This can save you megabytes of memory!

The encoder will always outputs fully standard compliant JSON. You can tweaks it too with a compile of flags to ask for JSON that can be safely embedded within HTML or pretty printing for us humans.

Performance

The performance of your JSON library is probably not going to be the bottleneck of your application software. But I personally do not like bloated software and take the performance of JSON.java very seriously and every so often go through the code benchmarking pieces of it and try to find faster ways to do the job (without sacrifying standard compliance or safety.)

That said, since day one—and even after compiliance fixed— JSON.java has always performed better than the old standard tool with akward API for the job; JSON-java. I have seen this in a few places and unsupprisingly it is also included with the Android API).

My attempt to benchmark the Jackson failed but maybe I will try it again later.

Of course, since I am talking about my own test results, you shouldn't really trust me but benchmark yourself. :-)

The deduplication feature meantioned above unfortunately did slow down the parser by maybe 25% but it is still plenty fast event with that. If you want to tweak for maximum speed, you may want to take that away and look at the Decoder.decodeNumber() method, too.

License

This library is released under the very permissive BSD 2-clause license.

2017-10-01 20:36:01 UTC

Examples

Here are some quick examples of what you can do and easy it is.

JSON.parse()

Lets start with a really basic thing; decoding a JSON string you got somewhere and you know it should contain a JSON object (e.g. a Map in the Java world).

...
String json = "{\"abc\":42}";
Map<String, Object> data = (Map<String, Object>) JSON.parse(json);
System.out.println(data.toString() + " (This is not JSON.)");
...
{abc=42} (This is not JSON.)

Note: You might get an unchecked warning about the cast.

Because the cast there is pretty unsafe, it is better to do something like this instead:

...
String json = "{\"abc\":42}";
JSONMap map = JSON.asMap(JSON.parse(json));
if (map != null) {
    System.out.println(map.toString() + " (This is not JSON.)");
}
...

(Same output as above.)

You should also catch the possible JSONException in case the JSON is not valid and cannot be parsed. There are other similar JSON.asX() functions for safe casting to different types.

JSON.parse() can also decode directly from any Reader so that you do not have to read everything into a String first.

JSON.stringify()

And another basic example of encoding a simple data

...
Map<String, Object> data = new HashMap<>();
data.put("strings", new String[] { "Hello", "World", "!" });
data.put("ints", new int[] { 1, 2, 3 });
data.put("floats", new float[] { 0.5f, 3.14159f, 2.71828f });
String json = JSON.stringify(data, JSON.FLAG_PRETTY);
System.out.println(json);
...
{
    "floats": [
        0.5, 3.14159, 2.71828
    ],
    "ints": [
        1, 2, 3
    ],
    "strings": [
        "Hello", "World", "!"
    ]
}

The API also supports outputting directly to any Appendable such as a StringBuilder or any Writer object.

Simply escaping a string for a <script> tag

Sometimes it is nice to be able to safely output JavaScript, for example, from a JSP page. You can use JSON.stringify() to safely escape your data to be included inside a <script> tag. (This also works for pure JavaScript but embedding in HTML is trickier.)

...
String text = "Is this \"<\" and that \">\" safe?";
System.out.println("<script>"
                   + "var text = "
                   + JSON.stringify(text, JSON.FLAG_HTML_SAFE)
                   + ";"
                   + "</script>");
...
<script>var text = "Is this \u0022\u003c\u0022 and that \u0022\u003e\u0022 safe?";</script>

The result is valid JSON but has extra escaping so that it can be safely embedded inside a HTML document.

Streaming output with JSONWriter

If you do not wish to create Map and/or List objects, you can also use JSONWriter to create a structure in code without any intermediate objects:

...
new JSONWriter(new OutputStreamWriter(System.out))
     .object()
       .name("foo")
       .value("bar")
       .name("arr")
       .array()
         .value(1)
         .value(2)
         .value(3)
       .end()
     .end()
     .close();
...
{"foo":"bar","arr":[1,2,3]}

Note: This example closes the System.out and it will be unwritable afterwards.

JSONWriter will throw an exception at runtime if the structure does not have a valid form (e.g. you cannot use name() within an array). Of course, it cannot detect ommitted end() calls if you never call the close() method either (which would result in unclosed arrays or objects and invalid JSON output.)

It supports all the same flags as JSON.stringify() as well as all the same value types in value(), and can output to any Appendable as well. For Writer objects, the flush() and close() methods will call the same method for the Writer object, too.

Streamed input with ???

Sorry, there is no JSONReader class.

JSONPath

TODO

2017-10-01 20:37:37 UTC

Documentation

Beside this web page, the only documentation is in the javadoc comments. I try to explain everything in more detail there and keep them up-to-date.

See the generated documentation for the public API.

Installing

Unless you copy the sources into you own projects, you will need Ant to build a jar file that you can include to your classpath. Simple ant jar should do it as long as you have the Error Prone and JUnit jars in your lib directory. See lib/README.

Or you can just do it the oldskool way and compile from command line with javac and use jar if plain class files are not enough.

2017-10-01 20:32:39 UTC

Test Cases

The sources now start to have a fair amount of JUnit tests which should cover most common cases as well as lots of corner cases were bugs (may) have been found earlier. Of course, more tests will be added if/when bugs are discovered—and fixed— or as new features are added.

The tests should run at without any failures and if they don't, you probably have something weird going on. As always, let me know if you encounter any bugs so they can get fixed.


I have run the parser tests from the JSONTestSuite (see Parsing JSON is a Minefield.) The results originally revealed one bug (unescaped control characters, fixed, later turned into an extension), one inconvinience of throwing StackOverflowError (now captured and wrapped as JSONException), and a few corner cases that have now been re-classified as implemenentation dependent. As far as I can tell, all of these cases are now handled adequately.

Note: JSON.java doesn't parse raw byte streams but Unicode decoding (and encoding) is handler by Java facilities. Therefore, I had to "cheat" on these test and specify the correct charset for each test case.

2017-10-01 20:40:33 UTC

Download

There are currently no tarballs, zips, or jars available for download. However, I feel like a 1.0 release may be coming soon(ish)...

In the mean time, you can get the source from: git clone https://git.gizmo.dy.fi/jsonjava.git.

2017-10-01 19:52:33 UTC

Email

You can reach me via email at vaino (dot) helminen (at) gmail (dot) com.