Friday, April 27, 2018

Transient field initialization when using GSON

When you use GSON to deserialize a JSON string in your Java code, the class has to have a non-argument constructor in order for the transient fields to be initialized properly:

package gsondemo;
import com.google.gson.Gson;
import java.util.Arrays;
/**
* GSON demo. Demonstrates effect of having no non-argument constructor on
* initialization of transient fields when creating an object from JSON string.
* Reference: https://stackoverflow.com/a/13532237/51358
* @author skorkmaz, April 2018, License: Public Domain
*/
public class GSONDemo {
static Gson gson = new Gson();
static class Base {
int val1 = 1;
//transient fields are not included in serialization:
transient int transientVal = 3;
transient int[] tansientArray = {1, 2, 3};
}
static class ClassWithImplicitNonArgConstructor extends Base {
}
static class ClassWithOnlyArgumentConstructor extends Base {
//No non-argument constructor -> When creating object from JSON string,
//transient fields will NOT be initialized
public ClassWithOnlyArgumentConstructor(int aVal) {
}
}
static class ClassWithExplicitNonArgConstructor extends Base {
public ClassWithExplicitNonArgConstructor(int aVal) {
}
//Non-argument constructor --> When creating object from JSON string,
//transient fields will be initialized
public ClassWithExplicitNonArgConstructor() {
}
}
public static void main(String[] args) {
// Serialization:
System.out.println("ClassWithImplicitNonArgConstructor");
System.out.println("----------------------------------");
Base obj11 = new ClassWithImplicitNonArgConstructor();
obj11.val1 = 500;
obj11.transientVal = 10;
//Transient fields will not be included in JSON:
String json1 = gson.toJson(obj11);
System.out.println("json = " + json1);
// Deserialization:
Base obj12 = gson.fromJson(json1, ClassWithImplicitNonArgConstructor.class);
System.out.println("value1 = " + obj12.val1);
//The default value of 3 (not the modified value of 10) will be written:
System.out.println("value3 = " + obj12.transientVal);
System.out.println("intArray = " + Arrays.toString(obj12.tansientArray));
System.out.println("\nClassWithOnlyArgumentConstructor");
System.out.println("--------------------------------");
Base obj21 = new ClassWithOnlyArgumentConstructor(1);
String json2 = gson.toJson(obj21);
System.out.println("json = " + json2);
Base obj22 = gson.fromJson(json2, ClassWithOnlyArgumentConstructor.class);
//will NOT have initial value in Base class:
System.out.println("value3 = " + obj22.transientVal);
//will NOT have initial value in Base class:
System.out.println("intArray = " + Arrays.toString(obj22.tansientArray));
System.out.println("\nClassWithExplicitNonArgConstructor");
System.out.println("----------------------------------");
Base obj31 = new ClassWithExplicitNonArgConstructor(1);
String json3 = gson.toJson(obj31);
System.out.println("json = " + json3);
Base obj32 = gson.fromJson(json3, ClassWithExplicitNonArgConstructor.class);
//will have initial value in Base class:
System.out.println("value3 = " + obj32.transientVal);
//will have initial value in Base class:
System.out.println("intArray = " + Arrays.toString(obj32.tansientArray));
}
}
view raw gsondemo.java hosted with ❤ by GitHub

The output of the above code is as follows:

ClassWithImplicitNonArgConstructor
----------------------------------
json = {"val1":500}
value1 = 500
value3 = 3
intArray = [1, 2, 3]

ClassWithOnlyArgumentConstructor
--------------------------------
json = {"val1":1}
value3 = 0
intArray = null

ClassWithExplicitNonArgConstructor
----------------------------------
json = {"val1":1}
value3 = 3
intArray = [1, 2, 3]