UPDATED: see a more up-to-date version here
Earlier I have published some results on performance of "simple" JSON
parsing -- simple meaning that processing is manual, to allow for
processing JSON using wide variety of Java+JSON tools available. This
includes processors from ultra-fast streaming processors (like Jackson)
all the way to "good old JSON.org" parser. But it also excluded at least
one potentially good tool (google-gson),
since it requires "untyped" access, ability to traverse arbitrary JSON
structure for testing.
Also: more and more access is nowadays done using a more convenient
class of tools, called data binding (or mapping; or sometimes
serialization) tools (libraries, packages). In such cases application
just asks library to convert JSON to a Java Object (or vice versa), and
that's about it. Very convenient; especially for strongly typed web
services.
So, with that background, let's see what are performance characteristics
of available tools.
1. JSON Data Binding: Contestants
Now, list of tools that allow doing is somewhat limited: I am aware of
following:
Given that all of them can do conversions with similar ease (at least
for simple Java types), is there much difference in performance? To
figure this out, I will be using somewhat incorrectly named StaxBind
(really, it should be renamed PojoBind or something) sub-project of
Woodstox. Data to bind is a simple rendition of tabular data, with List
of beans that contain personal information (name, address and so on);
document size (for this test) being about 2 kilobytes.
2. Results!
And yes, indeed, results
look vaguely familiar (see here,
for example). Considering the "bigger is better" aspect -- value
measured, "tps", is number of documents read, written, or
read-modify-written per second -- difference from slowest (google-gson)
to fastest (Jackson) is a solid order of magnitude.
Looks like Jackson still the King of JSON, regarding processing speed --
and by ridiculously high margin too... If you are already a Jackson
user, you may want to congratulate yourself on choosing a very efficient
(even green! save those cycles!) tool. A pat on your back might be
warranted as well. To put performance in perspective; being able to read ten
thousand 2k documents per second (throughput of about 20 megabytes
per second), on an almost obsolete AMD Athlon based PC (my home PC) is
not too shabby; and all this without little if any glue code.
Actually, as you can see, there is one (and only one!) thing faster than
Jackson Data Mapper: "raw" hand-written data mapper. And even that is
just a bit faster; probably only worth the extra hand-written code for
high-volume use cases, or where number of POJO types is very limited.
3. Some details
Given the big difference in perceived performance, avid readers might be
interested in reproducing results, or at least perusing source code. All
code is within "staxbind" module in the primary Codehaus
Woodstox SVN repository., and author (me!) can be contacted for more
details (for some reason Codehaus interface makes access sometimes bit
harder than needs be), questions and suggestions.
But there is nothing particularly complicated about code; here's how
core methods for tested packages actually look like (interfaces are
defined by StaxBind package itself; template T translates to "DbData"
(POJO type)).
3.1 Jackson test code
Jackson code is simplest of alternatives, as it supports direct
streaming access
public class StdJacksonConverter extends StdConverter
{
ObjectMapper mapper = new ObjectMapper();
//...
public T readData(InputStream in) throws IOException {
return _mapper.readValue(in, _itemClass);
}
public int writeData(OutputStream out, T data) throws Exception {
JsonGenerator jg = _jsonFactory.createJsonGenerator(out, JsonEncoding.UTF8);
_mapper.writeValue(jg, data);
jg.close();
return -1;
}
}
3.2 Json-tools test code
Test code here needs a couple of more lines, since there is no way to
directly go from POJOs to stream/String and back. But nothing excessive.
public class StdJsonToolsConverter extends StdConverter
{
final JSONMapper _mapper = new JSONMapper();
//...
public T readData(InputStream in) throws Exception {
// two-step process: parse to JSON value, bind to POJO
JSONParser jp = new JSONParser(in);
JSONValue v = jp.nextValue();
return (T) _mapper.toJava(v, _itemClass);
}
public int writeData(OutputStream out, T data) throws Exception {
JSONValue v = _mapper.toJSON(data);
String jsonStr = v.render(false);
OutputStreamWriter w = new OutputStreamWriter(out, "UTF-8");
w.write(jsonStr);
w.flush();
return -1;
}
}
3.3 Google-gson test code
This test code is bit shorter than Json-tools one, since package does
not use intermediate tree form. Surprisingly this does not seem to
translate to better performance, as the package ends up taking its time
doing conversions. On positive note, there should be plenty of room for
improvement in this area...
public class StdGsonConverter extends StdConverter
{
final Gson _gson = new Gson();
public T readData(InputStream in) throws IOException {
return _gson.fromJson(new InputStreamReader(in, "UTF-8"), _itemClass);
}
public int writeData(OutputStream out, T data) throws Exception {
OutputStreamWriter w = new OutputStreamWriter(out, "UTF-8");
this._gson.toJson(data, w);
w.flush();
return -1;
}
}