We can use private fields, they will be serialized.
All fields in the current class (and from all super classes) are included by default.
If a field is marked transient, (by default) it is ignored and not included in the JSON serialization or deserialization.
This implementation handles nulls correctly.
While serializing, a null field is omitted from the output.
While deserializing, a missing entry in JSON results in setting the corresponding field in the object to its default value: null for object types, zero for numeric types, and false for booleans.
If a field is synthetic, it is ignored and not included in JSON serialization or deserialization.
Fields corresponding to the outer classes in inner classes are ignored and not included in serialization or deserialization.
Anonymous and local classes are excluded. They will be serialized as JSON null and when deserialized their JSON value is ignored and null is returned. Convert the classes to static nested classes to enable serialization and deserialization for them.
We cannot serialize objects with circular references, since that will result in infinite recursion.
Serialization and De-serialization
First we need to create Gson object by using the class Gson, then we can use methods like fromJson & toJson to do objects and json conversion.
TypeToken
TypeToken is a class in Gson that helps capture and preserve generic type information.
TypeToken is essential when working with generic types in Gson, and understanding its proper usage helps in handling complex JSON structures effectively.
TypeToken instances should be created carefully and reused when possible for better performance.
Gson gson =newGson();int[] ints = {1,2,3,4,5};String[] strings = {"abc","def","ghi"};// Serializationgson.toJson(ints); // ==> [1,2,3,4,5]gson.toJson(strings); // ==> ["abc", "def", "ghi"]// Deserializationint[] ints2 =gson.fromJson("[1,2,3,4,5]",int[].class);// ==> ints2 will be same as ints
Collections Example
for the collections, we will be needing type tokens for conversion.
Gson gson =newGson();Collection<Integer> ints =Arrays.asList(1,2,3,4,5);// SerializationString json =gson.toJson(ints); // ==> [1,2,3,4,5]// DeserializationTypeToken<Collection<Integer>> collectionType =newTypeToken<Collection<Integer>>(){};Collection<Integer> ints2 =gson.fromJson(json, collectionType);// ==> ints2 is same as intsString json ="[\"Alice\", \"Bob\", \"Charlie\"]";// Use TypeToken to define the typeType listType =newTypeToken<List<String>>() {}.getType();// Deserialize JSON to List<String>List<String> names =gson.fromJson(json, listType);System.out.println("Names: "+ names);// Serialize List<String> back to JSONString jsonString =gson.toJson(names, listType);
Maps Examples
Gson by default serializes any java.util.Map implementation as a JSON object. Because JSON objects only support strings as member names, Gson converts the Map keys to strings by calling toString() on them, and using "null" for null keys:
String json ="[{\"Alice\": 25, \"Bob\": 30}, {\"Charlie\": 35, \"David\": 40}]";Gson gson =newGson();// Use TypeToken to define the typeType nestedType =newTypeToken<List<Map<String,Integer>>>() {}.getType();// Deserialize JSON to List<Map<String, Integer>>List<Map<String,Integer>> nestedList =gson.fromJson(json, nestedType);System.out.println("Nested List: "+ nestedList);// Serialize List<Map<String, Integer>> back to JSONString jsonString =gson.toJson(nestedList, nestedType);System.out.println("JSON: "+ jsonString);
If map keys are complex and toString method is not implemented, then this can lead to malformed encoded keys or can cause mismatch between serialization and deserialization of the keys.
A workaround for this can be to use enableComplexMapKeySerialization() to make sure the TypeAdapter registered for the Map key type is used for deserialization and serialization.
When you call toJson(obj), Gson calls obj.getClass() to get information on the fields to serialize. Similarly, you can typically pass MyClass.class object in the fromJson(json, MyClass.class) method. This works fine if the object is a non-generic type.
However, if the object is of a generic type, then the Generic type information is lost because of Java Type Erasure. To make it work properly we need to use TypeToken
fooType actually defines an anonymous local inner class containing a method getType() that returns the fully parameterized type.
{"status":"success","data": [ {"name":"Alice","age":25}, {"name":"Bob","age":30} ]}classApiResponse<T> {String status;T data;}classPerson {String name;int age;}importcom.google.gson.Gson;importcom.google.gson.reflect.TypeToken;importjava.lang.reflect.Type;importjava.util.List;publicclassMain {publicstaticvoidmain(String[] args) {String json ="{\"status\": \"success\", \"data\": [{\"name\": \"Alice\", \"age\": 25}, {\"name\": \"Bob\", \"age\": 30}]}";Gson gson =newGson();// Define the TypeToken for ApiResponse<List<Person>>Type responseType =newTypeToken<ApiResponse<List<Person>>>() {}.getType();// Deserialize JSON to ApiResponse<List<Person>>ApiResponse<List<Person>> response =gson.fromJson(json, responseType);System.out.println("Status: "+response.status);for (Person person :response.data) {System.out.println(person.name+" is "+person.age+" years old."); }// Serialize ApiResponse<List<Person>> back to JSONString jsonString =gson.toJson(response, responseType);System.out.println("JSON: "+ jsonString); }}
Custom Serialization and Deserialization
Sometimes the default representation is not what you want. This is often the case when dealing with library classes (DateTime, etc.). Gson allows you to register your own custom serializers and deserializers. This is done by defining two parts:
JSON Serializers: Need to define custom serialization for an object
JSON Deserializers: Needed to define custom deserialization for a type
Instance Creators: Not needed if no-args constructor is available or a deserializer is registered
The following example shows how to exclude fields marked with a specific @Foo annotation and excludes top-level types (or declared field type) of class String.