Jackson Vs Gson Comparison Essay

Which JSON library for Java can parse JSON files the fastest? (Updated: 13/8/17)

JSON is the accepted standard these days for transmitting data between servers and web applications, but like many things we’ve accepted, it’s easy to take it for granted and not put much further thought into it. We often don’t think about the JSON libraries we use, but there are some differences between them. With that in mind, we ran a benchmark test to see how fast four of the most popular JSON libraries for Java parse different sizes of files. Today, we’re sharing those results with you guys.

JSON is often used to transport and parse big files. This is a scenario that’s common in data processing applications running in Hadoop or Spark clusters. Given the size of these files, you can be looking at significant differences in parsing speed between libraries.

Small files come up all the time as incoming requests at high throughput, and parsing them happens quickly, so the differences in performance may not seem to be a big deal at first. But the differences add up, as often you need to parse lots of small files in rapid succession during times of heavy traffic. Micro services and distributed architectures often use JSON for transporting these kinds of files, as it’s the de facto format for web APIs.

Not all JSON libraries perform the same. Picking the right one for your environment can be critical. This benchmark can help you decide.

The JSON Libraries

JSON.simple vs GSON vs Jackson vs JSONP For the benchmark tests, we looked at four major JSON libraries for Java: JSON.simple, GSON, Jackson, and JSONP. All of these libraries are popularly used for JSON processing in a Java environment, and were chosen according to their popularity in Github projects. Here are the ones we tested:

  • Yidong Fang’s JSON.simple (https://github.com/fangyidong/json-simple). JSON.simple is a Java toolkit for encoding and decoding JSON text. It’s meant to be a lightweight and simple library that still performs at a high level.
  • Google’s GSON (https://github.com/google/gson). GSON is a Java library that converts Java Objects into JSON and vice versa. It provides the added benefit of full support for Java Generics, and it doesn’t require you to annotate your classes. Not needing to add annotations makes for simpler implementation and can even be a requirement if you don’t have access to your source code.
  • FasterXML’s Jackson Project (https://github.com/FasterXML/jackson). Jackson is a group of data processing tools highlighted by its streaming JSON parser and generator library. Designed for Java, it can also handle other non-JSON encodings. It’s the most popular JSON parser, according to our findings on Github usages.
  • Oracle’s JSONP (https://jsonp.java.net/). JSONP (JSON Processing) is a Java API for JSON processing, namely around consuming and producing streaming JSON text. It’s the open source reference implementation of JSR353.

The Benchmark

We ran a benchmark test on the libraries for both big files and small files. The requirements (and therefore performance) for handling different file sizes are different, as are the environments in which the need to parse these files arise.

The benchmark tested two key scenarios: parsing speed for big files (190 MB) and parsing speed for small files (1 KB). The big files were taken from here: https://github.com/zeMirco/sf-city-lots-json. The small files were randomly generated from here: http://www.json-generator.com/.

For both big and small files, we ran each file 10 times per library. Given the size of the big file, we did 10 iterations per run for each library. Each small file was iterated 10,000 times per run for each library. For the small files test, we didn’t retain the files in memory between iterations and the test was run on a c3.large instance on AWS.

The results for the big file are shown in full below, but I’ve further averaged the results for the small files in the interest of space. To view the extended results, go here. If you want to view the source code for the small files or the libraries, go here.

Big File Results

Big differences here! Depending on the run, Jackson or JSON.simple traded fastest times, with Jackson edging out JSON.simple in aggregate. Looking at the average result across all the test runs, Jackson and JSON.simple come out well ahead on the big file, with JSONP a distant third and GSON far in last place.

Let’s put that in percentage terms. Jackson is the winner in average time across all the runs. Looking at the numbers from two different angles, here are the percentage results:

Those are big differences between the library speeds!

Takeaway: It was a photo finish, but Jackson is your winning library. JSON.simple is a nose behind and the other two are in the rearview mirror.

Small Files Results

The table above shows the average of 10 runs for each file, and the total average at the bottom. The tally for fastest library on number of files won is:

  • GSON – 14
  • JSONP – 5
  • Jackson – 1
  • JSON.simple – 0

That seems pretty telling. However, looking at the average result for all the test runs across all the files, GSON is the winner here, with JSON.simple and JSONP taking a distinct second and third place, respectively. Jackson came in 2nd to last. So despite not being the fastest on any single file, JSON.simple is the second fastest in aggregate. And despite being the fastest on a handful of files, JSONP is well in third place in aggregate.

Of interest to note is that despite being the slowest library here, Jackson is very consistent across all the files, while the other three libraries are occasionally much faster than Jackson, but on some files end up running at about the same speed or even slightly slower.

Let’s put the numbers in percentage terms, again looking at the numbers from two different angles:

Compared to the big file tests, these are smaller differences, but still quite noticeable.

Takeaway: Bad luck for JSON.simple, as it again loses a close race, but GSON is your winner. JSONP is a clear third and Jackson brings up the rear.

Conclusion

Parsing speed isn’t the only consideration when choosing a JSON library, but it is an important one. Upon running this benchmark test, what we found was that there is no one library that blows the others away on parsing speed across all file sizes and all runs. The libraries that performed best for big files suffered for small files and vice versa.

Choosing which library to use on the merit of parsing speed comes down to your environment then.

  • If you have an environment that deals often or primarily with big JSON files, then Jackson is your library of interest. GSON struggles the most with big files.
  • If your environment primarily deals with lots of small JSON requests, such as in a micro services or distributed architecture setup, then GSON is your library of interest. Jackson struggles the most with small files.
  • If you end up having to often deal with both types of files, JSON.simple came in a very close 2nd place in both tests, making it a good workhorse for a variable environment. Neither Jackson nor GSON perform as well across multiple files sizes.

As far as parsing speed goes, JSONP doesn’t have much to recommend for it in any scenario. It performs poorly for both big and small files compared to other available options. Fortunately, Java 9 is reportedly getting native JSON implementation, which one would imagine is going to be an improvement over the reference implementation.

So there you have it. If you’re concerned about parsing speed for your JSON library, choose Jackson for big files, GSON for small files, and JSON.simple for handling both. Let me know if you have any thoughts on this benchmark in the comments.

Further reading:

5 Error Tracking Tools Java Developers Should Know

1. Introduction

In this article, we’ll compare the Gson and Jackson APIs for serializing and deserializing JSON data to Java objects and vice-versa.

Gson and Jackson are complete libraries offering JSON data-binding support for Java. Each are actively developed open-source projects which offer to handle of complex data types and support for Java Generics.

And in most cases, both libraries can deserialize to an entity without modifying an entity class, which is important in cases where a developer doesn’t have access to the entity source code.

2. Gson Maven Dependency 

<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>${gson.version}</version> </dependency>

You can get the latest version of Gson here.

3. Gson Serialization

Serialization converts Java objects to JSON output. Consider the following entities:

public class ActorGson { private String imdbId; private Date dateOfBirth; private List<String> filmography; // getters and setters, default constructor and field constructor omitted } public class Movie { private String imdbId; private String director; private List<ActorGson> actors; // getters and setters, default constructor and field constructor omitted }

3.1. Simple Serialization

Let’s start with an example of Java to JSON serialization:

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); ActorGson rudyYoungblood = new ActorGson( "nm2199632", sdf.parse("21-09-1982"), Arrays.asList("Apocalypto", "Beatdown", "Wind Walkers") ); Movie movie = new Movie( "tt0472043", "Mel Gibson", Arrays.asList(rudyYoungblood)); String serializedMovie = new Gson().toJson(movie);

This will result in:

{ "imdbId": "tt0472043", "director": "Mel Gibson", "actors": [{ "imdbId": "nm2199632", "dateOfBirth": "Sep 21, 1982 12:00:00 AM", "filmography": ["Apocalypto", "Beatdown", "Wind Walkers"] }] }

By default:

  • All properties are serialized because they have no null values
  • dateOfBirth field was translated with the default Gson date pattern
  • Output is not formatted and JSON property names correspond to the Java entities

3.2. Custom Serialization

Using a custom serializer allows us to modify the standard behavior. We can introduce an output formatter with HTML, handle null values, exclude properties from output, or add a new output.

ActorGsonSerializer modifies generation of JSON code for the ActorGson element:

public class ActorGsonSerializer implements JsonSerializer<ActorGson> { private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); @Override public JsonElement serialize(ActorGson actor, Type type, JsonSerializationContext jsonSerializationContext) { JsonObject actorJsonObj = new JsonObject(); actorJsonObj.addProperty("<strong>IMDB Code</strong>", actor.getImdbId()); actorJsonObj.addProperty("<strong>Date Of Birth</strong>", actor.getDateOfBirth() != null ? sdf.format(actor.getDateOfBirth()) : null); actorJsonObj.addProperty("<strong>N° Film:</strong> ", actor.getFilmography() != null ? actor.getFilmography().size() : null); actorJsonObj.addProperty("filmography", actor.getFilmography() != null ? convertFilmography(actor.getFilmography()) : null); return actorJsonObj; } private String convertFilmography(List<String> filmography) { return filmography.stream() .collect(Collectors.joining("-")); } }

In order to exclude the director property, the @Expose annotation is used for properties we want to consider:

public class MovieWithNullValue { @Expose private String imdbId; private String director; @Expose private List<ActorGson> actors; }

Now we can proceed with Gson object creation using the GsonBuilder class:

Gson gson = new GsonBuilder() .setPrettyPrinting() .excludeFieldsWithoutExposeAnnotation() .serializeNulls() .disableHtmlEscaping() .registerTypeAdapter(ActorGson.class, new ActorGsonSerializer()) .create(); SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); ActorGson rudyYoungblood = new ActorGson("nm2199632", sdf.parse("21-09-1982"), Arrays.asList("Apocalypto","Beatdown", "Wind Walkers")); MovieWithNullValue movieWithNullValue = new MovieWithNullValue(null, "Mel Gibson", Arrays.asList(rudyYoungblood)); String serializedMovie = gson.toJson(movieWithNullValue);

The result is the following:

{ "imdbId": null, "actors": [ { "<strong>IMDB Code</strong>": "nm2199632", "<strong>Date Of Birth</strong>": "21-09-1982", "<strong>N° Film:</strong> ": 3, "filmography": "Apocalypto-Beatdown-Wind Walkers" } ] }

Notice that:

  • the output is formatted
  • some property names are changed and contain HTML
  • null values are included, and the director field is omitted
  • Date is now in the dd-MM-yyyy format
  • a new property is present – N° Film
  • filmography is a formatted property, not the default JSON list

4. Gson Deserialization

4.1. Simple Deserialization

Deserialization converts JSON input into Java objects. To illustrate the output, we implement the toString() method in both entity classes:

public class Movie { @Override public String toString() { return "Movie [imdbId=" + imdbId + ", director=" + director + ", actors=" + actors + "]"; } ... } public class ActorGson { @Override public String toString() { return "ActorGson [imdbId=" + imdbId + ", dateOfBirth=" + dateOfBirth + ", filmography=" + filmography + "]"; } ... }

Then we utilize the serialized JSON and run it through standard Gson deserialization:

String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":" + "[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\","+ "\"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}"; Movie outputMovie = new Gson().fromJson(jsonInput, Movie.class); outputMovie.toString();

The output is us our entities, populated with the data from our JSON input:

Movie [imdbId=tt0472043, director=null, actors=[ActorGson [imdbId=nm2199632, dateOfBirth=Tue Sep 21 04:00:00 PDT 1982, filmography=[Apocalypto, Beatdown, Wind Walkers]]]]

As was the case with the simple serializer:

  • the JSON input names must correspond with the Java entity names, or they are set to null.
  • dateOfBirth field was translated with the default Gson date pattern, ignoring the time zone.

4.2. Custom Deserialization

Using a custom deserializer allows us to modify the standard deserializer behavior. In this case, we want the date to reflect the correct time zone for dateOfBirth.  We use a custom ActorGsonDeserializer on the ActorGson entity to achieve this:

public class ActorGsonDeserializer implements JsonDeserializer<ActorGson> { private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); @Override public ActorGson deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); JsonElement jsonImdbId = jsonObject.get("imdbId"); JsonElement jsonDateOfBirth = jsonObject.get("dateOfBirth"); JsonArray jsonFilmography = jsonObject.getAsJsonArray("filmography"); ArrayList<String> filmList = new ArrayList<String>(); if (jsonFilmography != null) { for (int i = 0; i < jsonFilmography.size(); i++) { filmList.add(jsonFilmography.get(i).getAsString()); } } ActorGson actorGson = new ActorGson(jsonImdbId.getAsString(), sdf.parse(jsonDateOfBirth.getAsString()), filmList); return actorGson; } }

We employed a SimpleDateFormat parser to parse the input date, accounting for the time zone.

Note that we could have decided to simply write a custom deserializer for only the Date, but the ActorGsonDeserializer offers a more detailed view of the deserialization process.

Also note that the Gson approach does not require modifying the ActorGson entity, which is ideal as we may not always have access to the input entity. We use the custom deserializer here:

String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":" + "[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\", + \"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}"; Gson gson = new GsonBuilder() .registerTypeAdapter(ActorGson.class,new ActorGsonDeserializer()) .create(); Movie outputMovie = gson.fromJson(jsonInput, Movie.class); outputMovie.toString();

The output is similar to the simple deserializer result, except the date uses correct time zone:

Movie [imdbId=tt0472043, director=null, actors=[ActorGson [imdbId=nm2199632, dateOfBirth=Tue Sep 21 12:00:00 PDT 1982, filmography=[Apocalypto, Beatdown, Wind Walkers]]]]

5. Jackson Maven Dependency

<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency>

You can get the latest version of Jackson here.

6. Jackson Serialization

6.1. Simple Serialization

Here we will use Jackson to obtain the same serialized content we had with Gson using the following entities. Note that the entity’s getters/setters must be public:

public class ActorJackson { private String imdbId; private Date dateOfBirth; private List<String> filmography; // required getters and setters, default constructor // and field constructor details omitted } public class Movie { private String imdbId; private String director; private List<ActorJackson> actors; // required getters and setters, default constructor // and field constructor details omitted } SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); ActorJackson rudyYoungblood = new ActorJackson("nm2199632",sdf.parse("21-09-1982"), Arrays.asList("Apocalypto","Beatdown","Wind Walkers") ); Movie movie = new Movie("tt0472043","Mel Gibson", Arrays.asList(rudyYoungblood)); ObjectMapper mapper = new ObjectMapper(); String jsonResult = mapper.writeValueAsString(movie);

The output is as follows:

{"imdbId":"tt0472043","director":"Mel Gibson","actors": [{"imdbId":"nm2199632","dateOfBirth":401439600000, "filmography":["Apocalypto","Beatdown","Wind Walkers"]}]}

Some notes of interest:

  • ObjectMapper is our Jackson serializer/deserializer
  • The output JSON is not formatted
  • By default, Java Date is translated to long value

6.2. Custom Serialization

We can create a Jackson serializer for ActorJackson element generation by extending StdSerializer for our entity. Again note that the entity getters/setters must be public:

public class ActorJacksonSerializer extends StdSerializer<ActorJackson> { private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); public ActorJacksonSerializer(Class t) { super(t); } @Override public void serialize(ActorJackson actor, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("imdbId", actor.getImdbId()); jsonGenerator.writeObjectField("dateOfBirth", actor.getDateOfBirth() != null ? sdf.format(actor.getDateOfBirth()) : null); jsonGenerator.writeNumberField("N° Film: ", actor.getFilmography() != null ? actor.getFilmography().size() : null); jsonGenerator.writeStringField("filmography", actor.getFilmography() .stream().collect(Collectors.joining("-"))); jsonGenerator.writeEndObject(); } }

We create a Movie entity to allow ignoring of the director field:

public class MovieWithNullValue { private String imdbId; @JsonIgnore private String director; private List<ActorJackson> actors; // required getters and setters, default constructor // and field constructor details omitted }

Now we can proceed with a custom ObjectMapper creation and setup:

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); ActorJackson rudyYoungblood = new ActorJackson( "nm2199632", sdf.parse("21-09-1982"), Arrays.asList("Apocalypto", "Beatdown","Wind Walkers")); MovieWithNullValue movieWithNullValue = new MovieWithNullValue(null,"Mel Gibson", Arrays.asList(rudyYoungblood)); SimpleModule module = new SimpleModule(); module.addSerializer(new ActorJacksonSerializer(ActorJackson.class)); ObjectMapper mapper = new ObjectMapper(); String jsonResult = mapper.registerModule(module) .writer(new DefaultPrettyPrinter()) .writeValueAsString(movieWithNullValue);

The output is formatted JSON that handles null values, formats the date, excludes the director field and shows new output of :

{ "actors" : [ { "imdbId" : "nm2199632", "dateOfBirth" : "21-09-1982", "N° Film: " : 3, "filmography" : "Apocalypto-Beatdown-Wind Walkers" } ], "imdbID" : null }

7. Jackson Deserialization

7.1. Simple Deserialization

To illustrate the output, we implement the toString() method in both Jackson entity classes:

public class Movie { @Override public String toString() { return "Movie [imdbId=" + imdbId + ", director=" + director + ", actors=" + actors + "]"; } ... } public class ActorJackson { @Override public String toString() { return "ActorJackson [imdbId=" + imdbId + ", dateOfBirth=" + dateOfBirth + ", filmography=" + filmography + "]"; } ... }

Then we utilize the serialized JSON and run it through Jackson deserialization:

String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\": [{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\", \"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}"; ObjectMapper mapper = new ObjectMapper(); Movie movie = mapper.readValue(jsonInput, Movie.class);

The output is us our entities, populated with the data from our JSON input:

Movie [imdbId=tt0472043, director=null, actors=[ActorJackson [imdbId=nm2199632, dateOfBirth=Tue Sep 21 04:00:00 PDT 1982, filmography=[Apocalypto, Beatdown, Wind Walkers]]]]

As was the case with the simple serializer:

  • the JSON input names must correspond with the Java entity names, or they are set to null,
  • dateOfBirth field was translated with the default Jackson date pattern, ignoring the time zone.

7.2. Custom Deserialization

Using a custom deserializer allows us to modify the standard deserializer behavior.

In this case, we want the date to reflect the correct time zone for dateOfBirth, so we add a DateFormatter to our Jackson ObjectMapper:

String jsonInput = "{\"imdbId\":\"tt0472043\",\"director\":\"Mel Gibson\", \"actors\":[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\", \"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}"; ObjectMapper mapper = new ObjectMapper(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); mapper.setDateFormat(df); Movie movie = mapper.readValue(jsonInput, Movie.class); movie.toString();

The output reflects the correct time zone with the date:

Movie [imdbId=tt0472043, director=Mel Gibson, actors=[ActorJackson [imdbId=nm2199632, dateOfBirth=Tue Sep 21 12:00:00 PDT 1982, filmography=[Apocalypto, Beatdown, Wind Walkers]]]]

This solution is clean and simple.

Alternatively, we could have created a custom deserializer for the ActorJackson class, registered this module with our ObjectMapper, and deserialized the date using the @JsonDeserialize annotation on the ActorJackson entity.

The disadvantage of that approach is the need to modify the entity, which may not be ideal for cases when we don’t have access to the input entity classes.

8. Conclusion

Both Gson and Jackson are good options for serializing/deserializing JSON data, simple to use and well documented.

Advantages of Gson:

  • Simplicity of toJson/fromJson in the simple cases
  • For deserialization, do not need access to the Java entities

Advantages of Jackson:

  • Built into all JAX-RS (Jersey, Apache CXF, RESTEasy, Restlet), and Spring framework
  • Extensive annotation support

You can find the code for Gson and Jackson on GitHub.

0 thoughts on “Jackson Vs Gson Comparison Essay”

    -->

Leave a Comment

Your email address will not be published. Required fields are marked *