Skip to content

Benchmarking Gson vs Jackson vs Moshi 2020

A couple weeks ago, I made a post on Gson vs Jackson vs Moshi by comparing them on a more general sense of view with performance being only one of the 3 criteria.

In that section, comparing their performances, I decided to use 3 other sources which had already done benchmarking for these libraries in the past, dating as recently as 2019. While this saved me doing the work, it also raised some interesting questions. The results weren’t always very consistent across the 3 posts and we can only guess whether this is due to a difference in code or changed performance with updated versions of each library.

So we’re going to be doing our own benchmark test for each of these 3 JSON parsers for Android.

Each test is going to be done within the context of Retrofit because that’s how most apps make network calls nowadays. We’ll be running the tests on the JVM and using MockWebServer to return responses of different lengths and we’ll have them returned as RxJava Singles.

I’ll be running each of these tests at least twice to make sure there aren’t any flukes.

Do note that this benchmarking test will only cover parsing JSON responses into Java (or well actually, Kotlin) objects and not the other way around.

 

Rules for the Tests

I have 3 Retrofit interfaces set up, one for each parser. I also have 3 different JSON responses saved, all lists of the JsonPlaceholder Posts of varying lengths. The short one has 14 lines of JSON code, the medium one has 602, and the long one has 10106.

data class PostGson(
    val userId: Int,
    val id: Int,
    val title: String,
    val body: String
)

This post class will of course be slightly varied for their Jackson and Moshi counterparts, but they all achieve the bare syntax needed to parse a post from the above API.

To avoid having the JVM startup time be a factor, I have one dummy test that runs before any of the actual tests. I also run a dummy test for each of the parsers to minimise the factor of any first-use-startup time affecting our tests.

Other things to note that Moshi is making use of its kapt functions, and Jackson is not using any annotations other than @JsonProperty (see the post linked in the beginning to see why these could affect performance).

1 Iteration

These are tests where each response is parsed only once by each parser.

Short

Medium

Long

Gson

6

14

35

Jackson

7

14

25

Moshi

8

11

24

Parsing time in milliseconds

There is negligible difference in any of the parsers. As you’d expect, longer JSON files take a little bit longer to parse. Do note that these timings may also fluctuate. Another run of the test may show that Moshi has a shorter ‘short’ parse time than Gson, so for all intents and purposes, we’re saying each parser is about equal in this regard.

1000 Iterations

We’ll see if we get different results by having each test parse the response a thousand times each.

Short

Medium

Long

Gson

0.53

0.81

4.20

Jackson

0.48

0.61

3.02

Moshi

0.38

0.61

3.57

Parsing time in seconds

Okay now we have some results to talk about. What’s interesting here is that Gson has the worst performance of the 3 for all sizes of JSON responses which is interesting because it’s supposed to be the most simplistic and lacking in features compared to the other 2. It is however the oldest and still 100% Java-based, which may well be a factor considering we are parsing the response into a Kotlin data class.

Jackson and Moshi have medium parsing times, but Jackson seems to have the fastest long response parsing time of the bunch, while Moshi had a slightly faster short response parsing time. These trends remained true no matter how many times I ran the tests.

5000 Iterations

For curiosity, I wanted to see the results if we bumped up the number of iterations yet again.

Short

Medium

Long

Gson

2.28

2.85

17.83

Jackson

1.63

2.82

16.47

Moshi

1.59

2.68

19.69

Parsing time in seconds

Now THIS is interesting. For short tests, only Gson has a noticeable slower parsing time. They’re all about same for medium tests, and for the long response tests, surprisingly Moshi has the worst performance of the bunch. This trend remained true for multiple runs of the test.

I’m completely clueless as to any assumptions why this might be the case, but all we can say for now is Moshi doesn’t seem to be up there in the performance department if you need straight up hard JSON parsing firepower.

And yes, I want to point out once again that I am using Moshi’s codegen capabilities.

5000 Iterations with more Jackson annotation

One assumption we made in the linked post above as to why Jackson in some tests had the slowest parsing time was due to use of some of its annotations, so let’s put that to the test.

@JsonIgnoreProperties(value = ["someid"])
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
data class PostJackson(
    @JsonProperty("userId")
    val userId: Int,
    @JsonProperty("id") val id: Int,
    @JsonProperty("title") val title: String,
    @JsonProperty("body") val body: String,
    @JsonIgnore val ignoredField: String = ""
)

Our old Jackson data class only used the @JsonProperty, but now I added a bunch of annotations that are ultimately useless. In theory, this should bump up our parsing time with Jackson by even just a little bit. Let’s put it to the test.

Short

Medium

Long

Jackson without annotations

1.63

2.82

16.47

Jackson with annotations

1.76

2.10

8.87

Parsing time in seconds

Okay WOW. I did not expect that in the slightest. Not only did the annotations cut down the parsing time, but it effectively halved the parsing time on the long response! It appears through (albeit this time, accidental) smart use of Jackson annotations, you can do wonders for your Jackson performance.

Parsing Larger Objects

Up till now, we’ve been parsing posts which only have 4 fields. This time, let’s try parsing Users from the JsonPlaceholder API. This API has a more complex structure than the simple Post so let’s see if that makes a difference in our results.

This is a test of 5000 iterations but with new data classes for parsing a User object. In theory, our parsing times should be longer across the board. We’ll see.

Short

Medium

Long

Gson

2.33 2.59 7.22

Jackson

2.46 2.34 4.81

Jackson (Annotations)

1.84 1.98 4.27

Moshi

1.75 2.14 4.50

Parsing time in seconds

I think the most interesting finding here is how the parsing time all across the board is significantly smaller than that of the tests using the posts endpoint, despite the User being a much more complex object than Post in its structure.

Again, Jackson using annotations takes the lead with Moshi not being far behind.

Conclusion

There are a few key takeaways here:

  • 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

One thing I left out for these tests is the Jackson Kotlin Module. It’s possible that Moshi’s competing edge in this competition is its Kotlin compatibility, which the base version of Jackson doesn’t have, but it does have a separate module for Kotlin support. Will the Kotlin support speed up performance for Jackson, or will the extra overhead actually cause a negative impact?

When I get some spare time, I’ll run those tests too, but for now, happy coding ༼ つ ◕_◕ ༽つ

 

Published inAndroidLibraries