#java #generics #gson #json-deserialization
#java #общие #gson #json-десериализация
Вопрос:
В мастер-классе для переменной Generic<Parent> generic
я передаю дочерний объект main()
. Во время сериализации я получаю правильный вывод. Но при десериализации дочерний объект отсутствует. Кто-нибудь может дать рекомендации.
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;
}
}
}
Ответ №1:
Проблема
Gson пытается десериализовать общее значение в Parent
, не Child
. Поскольку существует type
as null
, вы не видите данных в десериализованном объекте, который отображается как {}
. Если вы добавите child.setType("type");
, то выходные данные станут:
valMaster1
:{"id":2,"generic":{"t":{"name":"I am child","type":"type"}}}
valMaster2
:{"id":2,"generic":{"t":{"type":"type"}}}
Однако поле name
отсутствует в Parent
классе, но Child
класс и Gson просто понятия не имеют, к какому подклассу Parent
оно относится (если да), и полностью игнорируют значение, что является правильным поведением.
Решение
Я нахожу в основном два варианта (я использую конструктор all-args для краткости):
-
Повысьте значение параметра универсального типа с верхней границей до
Master
класса и укажите конкретныйChild
тип в точке десериализации, используяcom.google.gson.reflect.TypeToken
и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"}}}
-
Жестко закодируйте конкретный универсальный тип
Generic<Child>
внутриMaster
класса. Десериализация упрощается, но дизайн менее гибкий: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"}}}
Комментарии:
1. Я действительно считаю, что OP запрашивает идеальную сериализацию / десериализацию в оба конца, а не жесткое кодирование дочерних классов ad-hoc.
2. @fluffy: Вы прочитали первую пару фрагментов? Это ничего не говорит о жестком кодировании .
3. Да, я это сделал.
Type type = new TypeToken<Master<Child>>() {}.getType();
В вашем решении № 1.4. Пожалуйста, найдите обходное решение по адресу pastebin.com/fXL4r1s9
5. Выглядит хорошо для меня. Однако вам необходимо удалить поле,
type
объявленное изParent
. Спасибо. Я узнал кое-что новое. Не стесняйтесь добавлять ответ.