GSON Serialiser Example

5 years ago by in Articles, GSON Tagged: , , ,

Java objects can be converted into JSON strings using the Gson API (Homepage). In this article we will see how we can convert Java objects into JSON strings using both the default Gson implementation and custom implementation.

The readers of this article are encouraged to read the articles: Simple Gson Example and Gson Deserialiser Example, if they are not familiar with Gson. Furthermore, this article is structured in the same way as the article Gson Deserialiser Example and the same examples are used here.

Observation

Please note the we will use the terms format or serialise interchangeably in this article.

All code listed below is available at: http://java-creed-examples.googlecode.com/svn/gson/Gson Serialiser Example/. Most of the examples will not contain the whole code and may omit fragments which are not relevant to the example being discussed. The readers can download or view all code from the above link.

Simple Example

Consider the following Java object.

package com.javacreed.examples.gson.part1;

public class Book {

  private String[] authors;
  private String isbn10;
  private String isbn13;
  private String title;

  // Methods removed for brevity

}

This is a simple Java class representing a book. Say that we need to serialise this class into the following JSON object.

{
  "title": "Java Puzzlers: Traps, Pitfalls, and Corner Cases",
  "isbn-10": "032133678X",
  "isbn-13": "978-0321336781",
  "authors": [
    "Joshua Bloch",
    "Neal Gafter"
  ]
}

Gson can seriliase the Book class without any special configuration, just using the default configuration. Gson uses the Java field names as the JSON names and will serialise their values accordingly. If we take a closer look to the JSON sample shown above, we will see that the ISBN fields contain a minus sign: isbn-10 and isbn-13. Unfortunately, we cannot obtain these field names using teh default Gson configuration. One way to address this problem is to use annotations as described in the article: Gson Annotations Example. Using annotations we can define the JSON field names and Gson will take case of the rest. Another approach is to use a JsonSerialiser (Java Doc) as shown in the following example.

package com.javacreed.examples.gson.part1;

import java.lang.reflect.Type;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class BookSerialiser implements JsonSerializer {

    @Override
    public JsonElement serialize(final Book book, final Type typeOfSrc, final JsonSerializationContext context) {
        final JsonObject jsonObject = new JsonObject();
        //The serialisation code is missing

        return jsonObject;
    }
}

The above example is not complete and we still need to add the most important thing, which is the serialisation. Let’s understand this class before we make it more complex by adding more code to it.

The interface JsonSerializer requires a type, which is the type of object that we will be serialised. In this case, we are serialising the Java object of type Book into JSON object. The return type of the serialize() method must be an instance of type JsonElement (Java Doc). As described in more detail in the article: Gson Deserialiser Example, the JsonElement has four concrete types listed below:

  • JsonPrimitive (Java Doc) – such as a string or integer
  • JsonObject (Java Doc) – a collection of JsonElements indexed by thier name (of type String). This is similar to a Map<String, JsonElement> (Java Doc)
  • JsonArray (Java Doc) – a collection of JsonElements. Note that the array elements can be any of the four types and mixed types are supported.
  • JsonNull (Java Doc) – a null value
Types of JsonElement

Types of JsonElement

The above image shows all types of JsonElement. The JsonObject can be thought of a collection of name/value pairs where the values are of type JsonElement. Therefore, the values can yet be other objects.

Following is a complete example of our serialiser.

package com.javacreed.examples.gson.part1;

import java.lang.reflect.Type;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class BookSerialiser implements JsonSerializer {

    @Override
    public JsonElement serialize(final Book book, final Type typeOfSrc, final JsonSerializationContext context) {
        final JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("title", book.getTitle());
        jsonObject.addProperty("isbn-10", book.getIsbn10());
        jsonObject.addProperty("isbn-13", book.getIsbn13());

        final JsonArray jsonAuthorsArray = new JsonArray();
        for (final String author : book.getAuthors()) {
            final JsonPrimitive jsonAuthor = new JsonPrimitive(author);
            jsonAuthorsArray.add(jsonAuthor);
        }
        jsonObject.add("authors", jsonAuthorsArray);

        return jsonObject;
    }
}

We added some code here. Let us break this into smaller parts and understand each individual part before understanding the whole picture.

If we are to serialise this Java object, we first need to create the correct instance of the JsonElement. In our example we are returning an instance of JsonObject as our Book is an object as shown next.

    final JsonObject jsonObject = new JsonObject();

This object will be populated with our fields using the names we like as shown next

    // The variable 'book' is passed as a parameter to the serialize() method
    final JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty("title", book.getTitle());
    jsonObject.addProperty("isbn-10", book.getIsbn10());
    jsonObject.addProperty("isbn-13", book.getIsbn13());

Using the addProperty() (Java Doc) method we can add any Java primitive together with Strings and Numbers. Note that the property name must be unique, otherwise it will replace the previous value. This can be thought of a Map (Java Doc) holding all values index by their name.

More complex objects such as Java objects and arrays cannot be added using the method shown above. The JsonObject has another method called add() (Java Doc), which can be used instead as shown below.

    // The variable 'book' is passed as a parameter to the serialize() method
    jsonObject.addProperty("title", book.getTitle());
    jsonObject.addProperty("isbn-10", book.getIsbn10());
    jsonObject.addProperty("isbn-13", book.getIsbn13());

    final JsonArray jsonAuthorsArray = new JsonArray();
    for (final String author : book.getAuthors()) {
      final JsonPrimitive jsonAuthor = new JsonPrimitive(author);
      jsonAuthorsArray.add(jsonAuthor);
    }
    jsonObject.add("authors", jsonAuthorsArray);

We first create the JsonArray and added all authors to it. Different from Java, we do not need to define the size of the array when initialising it. In fact, despite its name, we can think of the JsonArray class more as a list rather than array. Finally the variable jsonAuthorsArray is added to the json object. Note that we can add the jsonAuthorsArray to the jsonObject before adding its elements.

Before we can use our serialiser, we need to register it with Gson as shown below.

package com.javacreed.examples.gson.part1;

import java.io.IOException;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Main {

  public static void main(final String[] args) throws IOException {
    // Configure GSON
    final GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Book.class, new BookSerialiser());
    gsonBuilder.setPrettyPrinting();
    final Gson gson = gsonBuilder.create();

    final Book javaPuzzlers = new Book();
    javaPuzzlers.setTitle("Java Puzzlers: Traps, Pitfalls, and Corner Cases");
    javaPuzzlers.setIsbn10("032133678X");
    javaPuzzlers.setIsbn13("978-0321336781");
    javaPuzzlers.setAuthors(new String[] { "Joshua Bloch", "Neal Gafter" });

    // Format to JSON
    final String json = gson.toJson(javaPuzzlers);
    System.out.println(json);
  }
}

By registering our serialiser, we are instructing Gson to using this serialiser whenever an object of type Book is serialised.

In the example shown above, we also instructed Gson to format the JSON object, by invoking the set pretty printing shown next.

    gsonBuilder.setPrettyPrinting();

While this is useful for tutorials and debugging, please avoid this in production environment as this may produce larger JSON objects (in terms of text size) due to the formatting. Furthermore, pretty printing has a slight performance cost as Gson has to format the JSON objects and indent these accordingly.

Running the above code will produce the desired JSON object. This concludes our first example of how to use a custom Gson serialiser to serialise Java objects into JSON objects. In the following section we will se how to serialise nested objects using Gson.

Nested Objects

In this example we will describe how to serialise nested objects, that is, objects within other objects. Here we will introduce a new entity, the author. A book, together with the title and ISBN can have a list of authors. The JSON object that will be produced in this example differs from the previous one to cater for the new entity as shown next:

{
  "title": "Java Puzzlers: Traps, Pitfalls, and Corner Cases",
  "isbn": "032133678X",
  "authors": [
    {
      "id": 1,
      "name": "Joshua Bloch"
    },
    {
      "id": 2,
      "name": "Neal Gafter"
    }
  ]
}

Note that in the previous example the authors were simply an array of strings as shown next:

  "authors": [
    "Joshua Bloch",
    "Neal Gafter"
  ]

In this example, the authors are JSON objects, not just primitives as shown next.

    {
      "id": 1,
      "name": "Joshua Bloch"
    }

The JSON author has an id and a name. Following is an example of the Author class.

package com.javacreed.examples.gson.part2;

public class Author {

  private int id;
  private String name;

  // Methods removed for brevity

}

This class is very straightforward. It comprise two fields, both JsonPrimitives. The Book class was modified to make use of the Author, as shown below.

package com.javacreed.examples.gson.part2;

public class Book {

  private Author[] authors;
  private String isbn;
  private String title;

  // Methods removed for brevity

}

The authors field was changed from an array of integers to an array of Authors. The BookSerialiser class has to be modified too in order to accommodate this change, as shown below.

package com.javacreed.examples.gson.part2;

import java.lang.reflect.Type;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class BookSerialiser implements JsonSerializer<Book> {

  @Override
  public JsonElement serialize(final Book book, final Type typeOfSrc, final JsonSerializationContext context) {
    final JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty("title", book.getTitle());
    jsonObject.addProperty("isbn", book.getIsbn());

    final JsonElement jsonAuthros = context.serialize(book.getAuthors());
    jsonObject.add("authors", jsonAuthros);

    return jsonObject;
  }
}

The serialisation of the authors is delegated to the context (an instance of JsonSerializationContext (Java Doc) passed as a parameter to the serialize() method). The context will serialise the given objects and return a JsonElement. In turn the context will try to locate a serialiser that can serialise the given object and if none are found, it uses the default mechanism. For the time being we will not write a serialiser for the Author class, but instead we will use the default one.

package com.javacreed.examples.gson.part2;

import java.io.IOException;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Main {

  public static void main(final String[] args) throws IOException {
    // Configure GSON
    final GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Book.class, new BookSerialiser());
    gsonBuilder.setPrettyPrinting();
    final Gson gson = gsonBuilder.create();

    final Author joshuaBloch = new Author();
    joshuaBloch.setId(1);
    joshuaBloch.setName("Joshua Bloch");

    final Author nealGafter = new Author();
    nealGafter.setId(2);
    nealGafter.setName("Neal Gafter");

    final Book javaPuzzlers = new Book();
    javaPuzzlers.setTitle("Java Puzzlers: Traps, Pitfalls, and Corner Cases");
    javaPuzzlers.setIsbn("032133678X");
    javaPuzzlers.setAuthors(new Author[] { joshuaBloch, nealGafter });

    final String json = gson.toJson(javaPuzzlers);
    System.out.println(json);
  }
}

The above example, creates and configures Gson to use our BookSerialiser. We created two authors and a book and serialised the book. This will produce the JSON object shown at the beginning of this section.

For completeness we will also include a serialiser for the Author class as shown below.

package com.javacreed.examples.gson.part2;

import java.lang.reflect.Type;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class AuthorSerialiser implements JsonSerializer<Author> {

  @Override
  public JsonElement serialize(final Author author, final Type typeOfSrc, final JsonSerializationContext context) {
    final JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty("id", author.getId());
    jsonObject.addProperty("name", author.getName());

    return jsonObject;
  }
}

The above serialiser introduces no new features and thus requires no explanation. In order to use this new serialiser we need to register it with the GsonBuilder (Java Doc).

This concludes the section about nested objects. Using the context, we can delegate the serialisation of nested objects to the context which will in turn locate the proper serialiser and produce the respective JsonElement. In the next and final section we will see how to deal with object references.

Object References

Objects refer to other objects and the books and authors classes are no exception. The same author can have many books. For example author Joshua Bloch (Author at Amazon), has several books. Using the serialiser described before, we will end up in duplicate authors.

Consider the following example:

package com.javacreed.examples.gson.part3;

import java.io.IOException;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Example1 {

  public static void main(final String[] args) throws IOException {
    // Configure GSON
    final GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setPrettyPrinting();
    final Gson gson = gsonBuilder.create();

    final Author joshuaBloch = new Author();
    joshuaBloch.setId(1);
    joshuaBloch.setName("Joshua Bloch");

    final Author nealGafter = new Author();
    nealGafter.setId(2);
    nealGafter.setName("Neal Gafter");

    final Book javaPuzzlers = new Book();
    javaPuzzlers.setTitle("Java Puzzlers: Traps, Pitfalls, and Corner Cases");
    javaPuzzlers.setIsbn("032133678X");
    javaPuzzlers.setAuthors(new Author[] { joshuaBloch, nealGafter });

    final Book effectiveJava = new Book();
    effectiveJava.setTitle("Effective Java (2nd Edition)");
    effectiveJava.setIsbn("0321356683");
    effectiveJava.setAuthors(new Author[] { joshuaBloch });

    final Book[] books = new Book[] { javaPuzzlers, effectiveJava };

    final String json = gson.toJson(books);
    System.out.println(json);
  }
}

Here we have two authors and two books. One of the author is shared between two books. Note that we have two author objects not three, as the instance representing Joshua Bloch is shared between both books. Finally note that we are not using any custom serialisers on purpose. The following is produced when executing the above code.

[
  {
    "authors": [
      {
        "id": 1,
        "name": "Joshua Bloch"
      },
      {
        "id": 2,
        "name": "Neal Gafter"
      }
    ],
    "isbn": "032133678X",
    "title": "Java Puzzlers: Traps, Pitfalls, and Corner Cases"
  },
  {
    "authors": [
      {
        "id": 1,
        "name": "Joshua Bloch"
      }
    ],
    "isbn": "0321356683",
    "title": "Effective Java (2nd Edition)"
  }
]

We have two JSON books and three JSON authors. The author: Joshua Bloch, shown below, is duplicated.

      {
        "id": 1,
        "name": "Joshua Bloch"
      }

This increases the size of the JSON object considerable, especially with more complex objects. Ideally, the book JSON object only contains the authors’ ids rather than the whole object. This resembles relational databases (Wiki) where the book has a foreign key (Wiki) to the authors table.

The Book class is modified to include a method that return just the authors’ ids as shown below.

package com.javacreed.examples.gson.part3;

public class Book {

  private Author[] authors;
  private String isbn;
  private String title;

  public Author[] getAuthors() {
    return authors;
  }

  public int[] getAuthorsIds() {
    final int[] ids = new int[authors.length];
    for (int i = 0; i < ids.length; i++) {
      ids[i] = authors[i].getId();
    }
    return ids;
  }

  // Other methods removed for brevity

}

When serialising the books we will use the authors’ id instead of the authors as shown next.

package com.javacreed.examples.gson.part3;

import java.lang.reflect.Type;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class BookSerialiser implements JsonSerializer {

  @Override
  public JsonElement serialize(final Book book, final Type typeOfSrc, final JsonSerializationContext context) {
    final JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty("title", book.getTitle());
    jsonObject.addProperty("isbn", book.getIsbn());

    final JsonElement jsonAuthros = context.serialize(book.getAuthorsIds());
    jsonObject.add("authors", jsonAuthros);

    return jsonObject;
  }
}

Using this serialiser we will obtain the following:

[
  {
    "title": "Java Puzzlers: Traps, Pitfalls, and Corner Cases",
    "isbn": "032133678X",
    "authors": [
      1,
      2
    ]
  },
  {
    "title": "Effective Java (2nd Edition)",
    "isbn": "0321356683",
    "authors": [
      1
    ]
  }
]

Now instead of the whole author object we have just the author’s ids. This approach requires less space than the previous one where the whole author is serialised. This will have a huge effect on larger object graphs.

This example concludes this article about serialisation. Here we saw how we can serialise Java objects into JSON strings using default and custom serialisation options.

Albert Attard

Albert Attard is a Java passionate and technical lead at a research group. You can find him on . Over the past years Albert worked on various Java projects including traditional server/client applications, modular applications, large data handling applications and concurrent data manipulation applications to name a few. He has a BSc degree from the University of London (Homepage) and an MSc Information Security with the same university. His MSc thesis (Book) received the 2012 SearchSecurity.co.UK award (Website).

14 Responses to “GSON Serialiser Example”


Anonymous
February 7, 2013 Reply

Really liked what you had to say in your post, thanks for the good read!

domenico
February 17, 2015 Reply

Hi,
just a comment that might help others.
With reference to the first example (before the Nested Object paragraph) the method
gsonBuilder.registerTypeAdapter(Book.class, new BookSerialiser());
is not going to register the new serialiser, at least in my case.
I had to use the method registerTypeHierarchyAdapter.
Regards,
Domenico

Randal
February 14, 2013 Reply

Excellent write-up. I certainly love this site.
Keep writing!

Abdullah
May 31, 2013 Reply

Great tutorial. Thanks.

JSON | Pearltrees
June 17, 2013 Reply

[…] GSON Serialiser Example | Java Creed […]

kavitha
November 5, 2013 Reply

Great tutorial…It helped me a lot…Thank u somuch.plz keep posting gson examples

Treble Snake
June 30, 2014 Reply

Hi!
Great article, thanks a lot.
But in the example code JsonSerializer parametrization () is missing. Maybe it was done by purpose, but I guess it’s a misprint, as it’s one of the key features.

Albert Attard Albert Attard
June 30, 2014 Reply

Thank you for pointing this out. Will look into the code and revert where necessary.

Aibol
August 20, 2014 Reply

I have some question: I used a set instead of an array error issues. How to solve it? i use nested objects. thank you

Albert Attard Albert Attard
August 20, 2014 Reply

I did not quite understand your question. Can you please provide an example?

Aibol
August 20, 2014 Reply

Thank you! I have resolved my problem.

Albert Attard Albert Attard
August 20, 2014 Reply

That’s great.

Simon
March 19, 2015 Reply

Hi! Thanks for you good article! Can you just fix the declaration of the class implements JsonSerializer to implements JsonSerializer to fix the example (in you first serializer example)

Thanks!

Albert Attard Albert Attard
March 22, 2015 Reply

Thank you for pointing this out. I am moving the examples to GitHub and will update this during the transition.

Leave a Comment


Time limit is exhausted. Please reload the CAPTCHA.