When it comes to the network layer of pretty much any app, Retrofit is the only constant. When it comes to the JSON Parser used to serialise data objects into requests, or deserialise responses into data objects, we have a few contenders.
Gson – Google’s own JSON Parser library for Android and the most popular of the bunch (sitting at 18.5k Github stars, vs 5.9k and 6.5k). It is the oldest as well, with its 1.0 version being released in 2008
Jackson – The longest competitor of Gson in an attempt to provide a faster and more feature-rich parser than its competitor. Fun fact, its 1.0 release in 2009 was codenamed “Hazelnut”, named after the fact that lots of people choke on nuts.
Moshi – The most modern of the 3 parsers having its first release was in 2015. It was created by Square, the same people who created Retrofit and includes some of the people who have worked on Gson in the past.
Will there be situations where one is better than the other? Maybe. Can we round them all up to determine an objective best? Well we’re about to find out.
Now this comparison isn’t gonna be another benchmarking test. There’s quite a number of those out there already.
If we’re weighing them out against each other, we need a criteria. We’ll be putting these parsers against each other in each of these categories:
- Reliability & error handling
Gson, Jackson, and Moshi are all complete JSON data-binding support for Java for serialising Java objects into JSON representations and vice versa. Out of these 3 however, only Jackson supports XML parsing.
All 3 also support custom type adapters which help greatly when it comes to parsing more complex API structures without having to flood your project with unnecessary data classes just for the sake of parsing your JSON response. All 3 also support generic types, and enough configurability for most common use cases.
As for differences? Gson is the simplest of the 3 but that means it’s the least feature-rich. Jackson has extensive annotation support.
Some of the Jackson annotations
These are annotations that can be used on both classes and properties to modify behaviour during serialisation or deserialisation. Take
@JsonIgnoreProperties for example. According to the Java doc:
“Annotation that can be used to either suppress serialization of properties (during serialization), or ignore processing of JSON properties read (during deserialization)”
Jackson has an extensive number of these annotations allowing for plenty of flexibility when it comes to serialisation and deserialisation that Gson either doesn’t have, or would require much more effort to do so.
What about Moshi then? Moshi is not short on the feature list either. You get qualifiers like
@HexColor int which allow for multiple JSON representations for a single Java type, and a good number of adapter convenience methods such as
JsonAdapter.failOnUnknown() that lets you reject unexpected JSON data.
Credits to swankjesse’s comment on this Reddit post.
However, Jackson’s XML support as well as its sheer number of annotations (on top of the fact that they’re built into easy to use annotations) brings it on top of the feature list. That’s a point for Jackson.
Reliability & Error Handling
Let’s first talk about Gson, because it has a few problems in this area. First of all, it’s a purely Java library. Any Kotlin enthusiast will tell you the single most important advantage it has over Java is nullable types, and that allows for their safe handling and in general, avoiding null pointer exceptions.
What does this mean for Gson? Since it’s a Java library, it instantiates your Kotlin classes without any regard for their nullability and thus, null values can be deserialised into your Kotlin non-null types and cause runtime errors.
Not to mention, Gson has other problems like leaking implementation details of platform types into your encoded JSON, has a broken
Date adapter installed into it by default, and makes use of weird HTML escaping.
These reasons, among others, were actually the inspiration behind the creation of Moshi which was created to address these problems that Gson had. Moshi also has some pretty decent Kotlin support and probably more to come.
Moshi language breakdown according to Github
When it comes to error handling, Moshi also prides itself on predictable exceptions. It would throw an
IOException on IO problems, and a
JsonDataException on type mismatches. Gson is “all over the place”.
As for Jackson, although its core module is purely Java, it does have a Kotlin support module. Jackson also has many unique exception classes which tell you exactly why serialisation / deserialisation isn’t working the way it should. Bealdung’s article on it explains it perfectly.
But looking into it deeper, many of these are problems that the library could’ve simply handled better to avoid the problem completely.
For this reason, Moshi takes the win when it comes to reliability and error handling.
Performance & Size
There are plenty of benchmarking tests that have been done for these parsers, but the latest one I found is in 2019, and they don’t seem to be within the context of Retrofit which is how most of us will be using these, so I decided to conduct my own tests.
Read the full test results here.
I’m gonna show the results of the 5000 iterations test, a test conducted by parsing the JSON Placeholder Posts API 5000 times on the JVM with each of the parsers.
Jackson with Annotations
But as a summary, here were the main takeaways from the test:
- Jackson seems to be the best performance-wise, but this fact only remains solidly true if you use its annotations to speed up its performance
- Moshi is not far behind Jackson in terms of performance
- Gson is showing its age here as a JSON parser as it’s a fair bit behind these 2 in terms of performance
- Complex objects don’t necessarily take longer to parse than smaller and simpler objects
As for the size, Jackson’s method count is far higher than either Gson’s or Moshi’s. Danny Damsky made this count in his article, so we’ll use that.
Danny Damsky’s August 2018 method count
Moshi comes shipped with the Okio package with more or less doubles its method count, but if you’re using other popular Square libraries such as OkHttp (which you probably are), then you’ve already got Okio so that becomes irrelevant.
But unless you’re really constrained for app size, Jackson’s major speed advantage gives it the win here.
Tallying up the points:
Gson – 0
Jackson – 2
Moshi – 1
Jackson takes the win here. Gson, quite expectedly didn’t excel in any aspect over the other two. I mean, it is the oldest after all.
Jackson is very feature rich especially with its many annotations and the fact that it supports parsing for XML and other formats beyond JSON. Despite that, excels in performance. In some cases, extremely so over the other 2 parsers.
Moshi is also great, with plenty of features to cover your parsing needs, some of which I haven’t seen from Jackson (such as allowing for multiple JSON representations for the same data type).
Initially I thought of including a fourth criteria. Ease of Use. I do think however that none of the 3 are particular hard to use in most common use cases. If you think this is worth any discussion, leave a comment below.
Are there situations where Gson and Jackson would be a more desirable pick than Moshi? For Gson, if you’re currently using it in a project without problem and don’t necessarily want to put in the time to do a migration for Moshi, then stay on Gson. The Gson team is still working to make sure Gson is as solid of a library as it can be.
I plugged this earlier in the performance section, but as the shameless man I am, I will plug it again. Check out the benchmarking test I did for these parsers.
Now in what situations does Moshi excel for Jackson? It is, after all, the more popular library by quite a bit.
If you got your reasons for picking Moshi over Jackson, please stick it down in the comments because I’d really like to know.
In any case, happy coding ༼ つ ◕_◕ ༽つ