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 HashMap
s and ArrayList
s 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 List
s, Map
s,
String
s, Number
s, Boolean
s, 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.
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
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.
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.
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
.
Email
You can reach me via email at vaino (dot) helminen (at) gmail (dot) com.