GSON - Gson
Jakob Jenkov |
GSON is Google's JSON parser and generator for Java. Google developed GSON for internal use but open sourced it later. GSON it reasonably easy to use, but in my opinion not as elegant as Jackson or Boon (the winner in my opinion). In this GSON tutorial I will take you through how to use GSON to parse JSON into Java objects, and serialize Java objects into JSON.
GSON contains multiple APIs which you can use to work with JSON. This tutorial covers the Gson
component which parses JSON into Java objects, or generates JSON from Java objects. In addition to the
Gson
component GSON also has a pull parser in the GSON JsonReader
component.
Before you can use GSON you must first install GSON in your Java project. I have explained that in its own text about GSON Installation .
Creating a Gson Instance
Before you can use GSON you must first create a new Gson
object. There are two ways to create a
Gson
instance:
- Using
new Gson()
- Creating a
GsonBuilder
instance and callingcreate()
on it.
Both of these ways to create a Gson
instance will be covered in this GSON tutorial.
new Gson()
You can create a Gson
object simply by creating it with the new Gson()
instruction.
Here is how creating a Gson
object looks:
Gson gson = new Gson();
Once you have created a Gson
instance you can start using it to parse and generate JSON.
GsonBuilder.build()
Another way to create a Gson
instance is to create a GsonBuilder()
and call its
create()
method. Here is an example of creating a GsonBuilder
and calling create()
:
GsonBuilder builder = new GsonBuilder(); Gson gson = builder.create();
Using a GsonBuilder
allows you to set configuration options on the GsonBuilder
before
creating the Gson
object. You will see examples of this later in this GSON tutorial.
Parsing JSON Into Java Objects
GSON can pase JSON into Java objects using the fromJson()
method of the Gson
object.
Here is an GSON example of parsing JSON into a Java object:
String json = "{\"brand\":\"Jeep\", \"doors\": 3}"; Gson gson = new Gson(); Car car = gson.fromJson(json, Car.class);
The first line of the example defines the JSON string to parse. The second line creates a Gson
instance.
The third line calls the gson.fromJson()
method which parses the JSON string into a Car
object.
The first parameter to fromJson()
is the JSON source. In the example above the JSON source is a string.
The second parameter to the fromJson()
method is the Java class to parse parse the JSON into an instance
of. The Gson
instance creates an instance of this class and parses the JSON into it. Thus you should
make sure that this class has a no-arg constructor, or GSON cannot use it.
Here is how the Car
class looks:
public class Car { public String brand = null; public int doors = 0; }
Generating JSON From Java Objects
GSON can also generate JSON from Java objects. You do so via the Gson
object. To generate JSON you
call the toJson()
method of the Gson
object. Here is an example of generating JSON from
a Java object with GSON:
Car car = new Car(); car.brand = "Rover"; car.doors = 5; Gson gson = new Gson(); String json = gson.toJson(car);
Pretty Printing
By default the Gson
instance created with new Gson()
prints (generates) as compact as
possible JSON. Here is an example of the compact JSON output from a default Gson
instance:
{"brand":"Rover","doors":5}
However, this compact JSON can be hard to read. Therefore GSON offers a pretty printing option
where the JSON is printed so it is more readable in a text editor. Here is an example of how to create a
Gson
instance with pretty print enabled:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Here is an example of how the same JSON would look pretty printed:
{ "brand": "Rover", "doors": 5 }
Excluding Fields
You can tell GSON to exclude fields from your Java classes from being serialized. There are several ways to tell GSON to exclude a field. The following sections of GSON tutorial will look at the most useful and easy to use ways to exclude fields.
Transient Fields
If you make a field in a Java class transient
then GSON will ignore it in both serialization and
deserialization. Here is how the Car
class from earlier looks with the brand
field
marked as transient
:
public class Car { public transient String brand = null; public int doors = 0; }
The @Expose Annotation
The GSON @Expose
annotation (com.google.gson.annotations.Expose
) can be used to mark a
field to be exposed or not (included or not) when an object is serialized or deserialized.
The @Expose
annotation can take two parameters. Each
parameter is a boolean
which can take either the value true
or false
.
Here are some GSON @Expose
annotation examples to show what I mean:
@Expose(serialize = true); @Expose(serialize = false); @Expose(deserialize = true); @Expose(deserialize = false); @Expose(serialize = true , deserialize = false); @Expose(serialize = false, deserialize = true);
The @Expose
annotation's serialize
parameter specifies if the field annotated with the
@Expose
annotation should be included when the owning object is serialized. The deserialize
parameter specifies whether that field should be read when the owning object is deserialized.
Here is an example class using the GSON @Expose
annotation:
public class Car { @Expose(serialize = false, deserialize = false) public String brand = null; @Expose(serialize = true, deserialize = true) public int doors = 0; }
Notice the @Expose
annotation above the fields, telling whether the given field should
be included when serialized or deserialized.
In order to get GSON to react to the @Expose
annotations you must create a Gson
instance using the GsonBuilder
class. Here is how that looks:
GsonBuilder builder = new GsonBuilder(); builder.excludeFieldsWithoutExposeAnnotation(); Gson gson = builder.create();
Note, that this configuration makes GSON ignore all fields that do not have an @Expose
annotation. To have a field included in serialization or deserialization it must have an @Expose
annotation above it.
GsonBuilder.setExclusionStrategies()
Another way to exclude a field of a class from serialization or deserialization in GSON is to set an
ExclusionStrategy
on a GsonBuilder
, and use that GsonBuilder
to build
the Gson
object with.
ExclusionStrategy
is an interface, so you will have to create a class that implements the
ExclusionStrategy
interface. Here is an example that implements the ExclusionStrategy
interface with an anonymous class:
ExclusionStrategy exclusionStrategy = new ExclusionStrategy() { public boolean shouldSkipField(FieldAttributes fieldAttributes) { if("brand".equals(fieldAttributes.getName())){ return true; } return false; } public boolean shouldSkipClass(Class> aClass) { return false; } };
Notice that inside the shouldSkipField()
method of the ExclusionStrategy
implementation
the example checks if the given field name is brand
. If it is, that field is excluded from
serialization and deserialization.
To use the ExclusionStrategy
implementation create a GsonBuilder
and set the
ExclusionStrategy
on it using the setExclusionStrategies()
method, like this:
GsonBuilder builder = new GsonBuilder(); builder.setExclusionStrategies(exclusionStrategy); Gson gson = builder.create();
The exclusionStrategy
variable has to point to an implementation of the ExclusionStrategy
interface.
Serializing Null Fields
By default the Gson
object does not serialize fields with null
values to JSON. If
a field in a Java object is null
, Gson
excludes it.
You can force Gson
to serialize null
values via the GsonBuilder
.
Here is an example showing how to force serialization of null
values with GSON:
GsonBuilder builder = new GsonBuilder(); builder.serializeNulls(); Gson gson = builder.create(); Car car = new Car(); car.brand = null; String json = gson.toJson(car); System.out.println(json);
Notice the call to serializeNulls()
on the GsonBuilder
instance before creating
the Gson
object. Once serializeNulls()
has been called the Gson
instance
created by the GsonBuilder
will include null
fields in the serialized JSON.
The output from the above example would be:
{"brand":null,"doors":0}
Notice how the brand
field is null.
Custom Instance Creators in GSON
By default GSON will try to create an instance of a given class by calling the no-arg constructor of that class. However, if a given class does not have a default constructor, or you want to do some default configuration of the instance, or if you want to create an instance of a subclass instead, you need to create and register your own instance creator.
A GSON instance creator is simply an object factory. An instance creator has to implement the
InstanceCreator
interface (com.google.gson.InstanceCreator
). Here is an example
InstanceCreator
implementation:
import com.google.gson.InstanceCreator; public class CarCreator implements InstanceCreator<Car> { public Car createInstance(Type type) { Car car = new Car(); car.brand = "Toyota"; return car; } }
You use the above CarCreator
class by registering it on a GsonBuilder
before you create
the Gson
instance. Here is an example:
GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Car.class, new CarCreator()); Gson gson = gsonBuilder.create();
Now the Gson
instance will use the CarCreator
instance to create Car
instances. You can prove that to yourself by running this code (after the CarCreator
has been registered):
String carJson = "{ \"doors\" : 4 }"; Car car = gson.fromJson(carJson, Car.class); System.out.println(car.brand);
The default brand
property value is null
and the JSON string does not contain a
brand
property. Therefore you will see the value for the brand
property set inside
the CarCreator
's createInstance()
method (Toyota
).
Version Support in GSON
GSON contains simple version support for the Java objects it reads and writes. GSON version support means that you can mark fields in your Java classes with a version number, and then have GSON include or exclude fields from your Java classes based on their version number.
To use GSON version support you must first annotate your Java classes with the GSON @Since
annotation.
Here is an example Person
class with its fields annotated with the @Since
annotation:
import com.google.gson.annotations.Since; public class Person { @Since(1.0) public String firstName = null; @Since(1.0) public String lastName = null; @Since(2.0) public String middleName = null; @Since(3.0) public String email = null; }
Second, you must create a GsonBuilder
and tell it what version it should be serializing to and
deserializing from. Here is an example of how you create a GsonBuilder
and set the version number on it:
GsonBuilder builder = new GsonBuilder(); builder.setVersion(2.0); Gson gson = builder.create();
The Gson
instance created from the above GsonBuilder
will now just include fields that
are annotated with @Since(2.0)
or a lower version number than 2.0 . In the Person
example
class above that means the fields firstName
, lastName
and middleName
.
The email
field is annotated with version 3.0 which is later than 2.0, so GSON will exclude the email
field.
Here is an example of serializing a Person
object to JSON and look at the generated JSON:
Person person = new Person(); person.firstName = "John"; person.lastName = "Doe"; person.middleName = "Blocks"; person.email = "john@doe.com"; GsonBuilder builder = new GsonBuilder(); builder.setVersion(2.0); Gson gson = builder.create(); String personJson = gson.toJson(person); System.out.println(personJson);
This example will print out the following JSON string:
{"firstName":"John","lastName":"Doe","middleName":"Blocks"}
Notice how GSON excluded the email
field in the generated JSON.
Excluding fields based on version works the same for reading JSON into Java objects (deserialization).
Look at the following JSON string which contains all the fields, including the email
field:
"{\"firstName\":\"John\",\"lastName\":\"Doe\",\"middleName\":\"Blocks\",\"email\":\"john@doe.com\"}"
If you were to read a Person
object with the above Gson
object, the email
field will not be read even if it is present in the JSON string. Here is how reading a Person
object with the above Gson
instance would look:
String personJson2 = "{\"firstName\":\"John\",\"lastName\":\"Doe\",\"middleName\":\"Blocks\",\"email\":\"john@doe.com\"}"; Person personRead = gson.fromJson(personJson2, Person.class);
Custom Serialization and Deserialization
GSON offers the possibility for you to plug in customer serializers and deserializers. Your custom serializers can convert Java values to custom JSON, and your custom deserializers can convert custom JSON to Java values again.
Custom Serializer
A custom serializer in GSON has to implement the JsonSerializer
interface. The JsonSerializer
interface looks like this:
public interface JsonSerializer<T> { public JsonElement serialize(T value, Type type, JsonSerializationContext jsonSerializationContext) { } }
Implementing a custom serializer that can serializer boolean
values looks like this:
public class BooleanSerializer implements JsonSerializer<Boolean> { public JsonElement serialize(Boolean aBoolean, Type type, JsonSerializationContext jsonSerializationContext) { if(aBoolean){ return new JsonPrimitive(1); } return new JsonPrimitive(0); } }
Notice how the T
type parameter is replaced with the Boolean
class in two places.
Inside the serialize()
method you can convert the value (a Boolean
in this cas) to
a JsonElement
which the serialize()
method is required to return. In the example
above we use a JsonPrimitive
which is also a JsonElement
. As you can see, boolean
values of true
are converted to 1 and false
to 0, instead of true
and false
normally used in JSON.
Registering this custom serializer is done like this:
GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Boolean.class, new BooleanSerializer()) ; Gson gson = builder.create();
It is the call to registerTypeAdapter()
which registers the customer serializer with GSON.
Once registered, the Gson
instance created from the GsonBuilder
will use the
custom serializer. To see how that works we will use the following POJO class:
public class PojoWithBoolean { public String username = null; public Boolean isSuperUser = false; }
Here is how serializing a PojoWithBoolean
instance looks:
PojoWithBoolean pojo = new PojoWithBoolean(); pojo.username = "abc"; pojo.isSuperUser = false; String pojoJson = gson.toJson(pojo); System.out.println(pojoJson);
The output printed from this example would be:
{"username":"abc","isSuperUser":0}
Notice how the false
value of isSuperUser
is converted to a 0.
Custom Deserializer
GSON also provides support for custom deserializers. A custom deserializer must implement the
JsonDeserializer
interface. The JsonDeserializer
interface looks like this:
public interface JsonDeserializer<T> { public Boolean deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException; }
Implementing a custom deserializer for the Boolean
type would look like this:
public class BooleanDeserializer implements JsonDeserializer<Boolean> { public Boolean deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { return jsonElement.getAsInt() == 0 ? false : true; } }
Registering the custom deserializer with GSON is done using another version of the registerTypeConverter()
method. Here is how registering the above deserializer with GSON looks:
GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Boolean.class, new BooleanDeserializer()); Gson gson = builder.create();
And here is how parsing a JSON string with the created Gson
instance looks:
String jsonSource = "{\"username\":\"abc\",\"isSuperUser\":1}"; PojoWithBoolean pojo = gson.fromJson(jsonSource, PojoWithBoolean.class); System.out.println(pojo.isSuperUser);
The output printed from this GSON custom deserializer example would be:
true
... since the 1 in the JSON string would be converted to the boolean value true
.
Tweet | |
Jakob Jenkov |