下面的例子显示了一个类(Club),它包含一个抽象类(Member)的集合。我不知道我是否需要TypeAdapter或JsonDeserializer来使反序列化正确工作。序列化在没有任何帮助的情况下工作得很好,但是反序列化会抛出异常。为了说明我构建了下面的“克隆”测试。如果有人能提供一个工作示例,我将非常感激。
头等舱
package gson.test;
import java.util.ArrayList;
import com.google.gson.Gson;
public class Club {
public static void main(String[] args) {
// Setup a Club with 2 members
Club myClub = new Club();
myClub.addMember(new Silver());
myClub.addMember(new Gold());
// Serialize to JSON
Gson gson = new Gson();
String myJsonClub = gson.toJson(myClub);
System.out.println(myJsonClub);
// De-Serialize to Club
Club myNewClub = gson.fromJson(myJsonClub, Club.class);
System.out.println(myClub.equals(myNewClub) ? "Cloned!" : "Failed");
}
private String title = "MyClub";
private ArrayList<Member> members = new ArrayList<Member>();
public boolean equals(Club that) {
if (!this.title.equals(that.title)) return false;
for (int i=0; i<this.members.size(); i++) {
if (! this.getMember(i).equals(that.getMember(i))) return false;
}
return true;
}
public void addMember(Member newMember) { members.add(newMember); }
public Member getMember(int i) { return members.get(i); }
}
现在是抽象基类成员
package gson.test;
public abstract class Member {
private int type;
private String name = "";
public int getType() { return type; }
public void setType(int type) { this.type = type; }
public boolean equals(Member that) {return this.name.equals(that.name);}
}
以及会员的两个具体子类(黄金级和银级)
package gson.test;
public class Gold extends Member {
private String goldData = "SomeGoldData";
public Gold() {
super();
this.setType(2);
}
public boolean equals(Gold that) {
return (super.equals(that) && this.goldData.equals(that.goldData));
}
}
package gson.test;
public class Silver extends Member {
private String silverData = "SomeSilverData";
public Silver() {
super();
this.setType(1);
}
public boolean equals(Silver that) {
return (super.equals(that) && this.silverData.equals(that.silverData));
}
}
最后是输出
{"title":"MyClub","members":[{"silverData":"SomeSilverData","type":1,"name":""},{"goldData":"SomeGoldData","type":2,"name":""}]}
Exception in thread "main" java.lang.RuntimeException: Failed to invoke public gson.test.Member() with no args
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:107)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:186)
...
3条答案
按热度按时间azpvetkf1#
你可以两者都做。你选择哪一个实际上取决于潜在的性能影响,以及有多少代码愿意写。
反序列化器的开销更大。这是因为反序列化器的输入是一个json树,GSon必须为匹配你的类的元素创建一个完整的JsonElement子树,然后才能将它传递给反序列化器。如果你的模型有很多嵌套,开销会增加。对于普通对象,开销可以忽略不计。
看起来您将知道基于将包含在目标对象中的
type
属性的值创建哪个类。JsonElement
对象,读取type
属性,确定类型context.deserialize()
您的类型适配器必须更加复杂。类型适配器的输入是一个流,而不是一个元素/子树。您可以完全从流中加载下一个值,解析它,然后完全按照反序列化器所做的那样进行操作,这没有意义,您可以只使用反序列化器。或者,您可以读取流,查看有哪些属性,将它们保存到局部变量中,直到到达
type
属性(无法预测它的位置),然后阅读其余属性,并基于类型创建最终的Gold
/Silver
对象,读取并保存所有属性。krugob8w2#
好的,这是一个真实的的工作示例(这次我非常确定)。
俱乐部
成员抽象类
具体子类银和金
自定义成员序列化程序
自定义反序列化程序
还有输出
我应该注意到,我的真实的用例是性能不应该成为问题的用例,我从jSon文本文件加载对象缓存,因此执行此代码的频率使得性能远不如可维护性重要。
j5fpnvbx3#
看起来序列化/反序列化类层次结构是一个常见的问题。
甚至还有一个“官方”解决方案,在官方源代码存储库的
extras
目录中(不幸的是,它不是Maven包的一部分)。请检查: