Reputation: 83
In Master class for the variable Generic<Parent> generic
i am passing a Child Object in main()
. During serializing i am getting correct output. But while deserializing Child Object is missing. Could anyone give suggesstions.
public class GenericSample {
public static void main(String[] args) {
Generic<Parent> generic = new Generic<Parent>();
Child child = new Child();
child.setName("I am child");
generic.setT(child);
Gson gson = new Gson();
Master master = new Master();
master.setId(2);
master.setGeneric(generic);
String valMaster = gson.toJson(master);
System.out.println(valMaster);
/*
* Output: {"id":2,"generic":{"t":{"name":"I am child"}}}
*/
Master master2 = gson.fromJson(valMaster, Master.class);
String valMaster2 = gson.toJson(master2);
System.out.println(valMaster2);
/*
* Child Object is missing
* Output: {"id":2,"generic":{"t":{}}}
*/
}
static class Master {
private int id;
private Generic<Parent> generic;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Generic<Parent> getGeneric() {
return generic;
}
public void setGeneric(Generic<Parent> generic) {
this.generic = generic;
}
}
static class Generic<T> {
T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
static class Parent {
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
static class Child extends Parent {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
Upvotes: 1
Views: 686
Reputation: 44456
Problem
Gson tries to deserialize the generic value into Parent
, not Child
. Since there is type
as null
, you can see no data in the object deserialized which appears as {}
. If you add child.setType("type");
then the outputs become:
valMaster1
: {"id":2,"generic":{"t":{"name":"I am child","type":"type"}}}
valMaster2
: {"id":2,"generic":{"t":{"type":"type"}}}
However, the field name
is not present in the Parent
class but the Child
class and Gson simply has no idea what subclass of Parent
it is (if so) and completely ignores the value, which is a correct behavior.
Solution
I find basically two choices (I use all-args constructor for sake of brevity):
Elevate the upper-bounded generic type parameter to the Master
class and specify the particular Child
type at the point of deserialization using com.google.gson.reflect.TypeToken
and java.lang.reflect.Type
:
static class Master<T extends Parent> {
private int id;
private Generic<T> generic;
/* getters, setters and all-args constructor */
}
Child child = new Child("I am child");
Generic<Parent> generic = new Generic<>(child);
Master<Parent> master = new Master<>(2, generic);
Gson gson = new Gson();
String valMaster = gson.toJson(master);
System.out.println(valMaster);
// {"id":2,"generic":{"t":{"name":"I am child"}}}
Type type = new TypeToken<Master<Child>>() {}.getType();
Master<Child> master2 = gson.fromJson(valMaster, type);
String valMaster2 = gson.toJson(master2);
System.out.println(valMaster2);
// {"id":2,"generic":{"t":{"name":"I am child"}}}
Hardcode the particular generic type Generic<Child>
inside the Master
class. The deserialization gets the way easier, yet the design is less flexible:
static class Master {
private int id;
private Generic<Child> generic;
/* getters, setters and all-args constructor */
}
Child child = new Child("I am child");
Generic<Child> generic = new Generic<>(child);
Master master = new Master(2, generic);
Gson gson = new Gson();
String valMaster = gson.toJson(master);
System.out.println(valMaster);
// {"id":2,"generic":{"t":{"name":"I am child"}}}
Master master2 = gson.fromJson(valMaster, Master.class);
String valMaster2 = gson.toJson(master2);
System.out.println(valMaster2);
// {"id":2,"generic":{"t":{"name":"I am child"}}}
Upvotes: 1