我试图通过Gson框架学习java bean的继承和反序列化的概念。有关java bean类和json文件的详细信息如下所示。
ParentBean.java
public class ParentBean {
protected String key1;
protected String key2;
public ParentBean(String key1, String key2) {
super();
this.key1 = key1;
this.key2 = key2;
}
}
Bean1.java
public class Bean1 extends ParentBean {
private String key3;
public Bean1(String key1, String key2, String key3) {
super(key1, key2);
this.key3 = key3;
}
}
Bean2.java
public class Bean2 extends ParentBean {
private String key4;
public Bean2(String key1, String key2, String key4) {
super(key1, key2);
this.key4 = key4;
}
}
bean1.json
{
"key1":"value1",
"key2":"value2",
"key3":"value33"
}
bean2.json
{
"key1":"value1",
"key2":"value2",
"key4":"value43"
}
为了探索有关继承和反序列化的事情,我使用了以下代码:
Usage.java
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
public class Usage {
public static void main(String[] args) throws FileNotFoundException {
RuntimeTypeAdapterFactory<ParentBean> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory
.of(ParentBean.class, "type")
.registerSubtype(Bean1.class, "bean1")
.registerSubtype(Bean2.class, "bean2");
Gson gson = new GsonBuilder().registerTypeAdapterFactory(runtimeTypeAdapterFactory).create();
FileReader fr = new FileReader("bean1.json");
Type pType = new TypeToken<ParentBean>(){}.getType();
ParentBean pb = gson.fromJson(fr, pType);
if (pb instanceof Bean1) {
System.out.println(" Bean1");
} else if (pb instanceof Bean2) {
System.out.println("Bean2");
}
}
}
我收到的错误堆栈如下:
Exception in thread "main" com.google.gson.JsonParseException: cannot deserialize class inheritance.ParentBean because it does not define a field named type
at com.google.gson.typeadapters.RuntimeTypeAdapterFactory$1.read(RuntimeTypeAdapterFactory.java:205)
at com.google.gson.TypeAdapter$1.read(TypeAdapter.java:199)
at com.google.gson.Gson.fromJson(Gson.java:795)
at com.google.gson.Gson.fromJson(Gson.java:761)
at inheritance.Usage.main(Usage.java:23)
为了寻找解决方案,我遇到了this堆栈溢出讨论。不幸的是讨论是关于create()方法的。错误堆栈表示问题出在第23行,此行包含fromJson()
方法。
答案 0 :(得分:2)
您需要告诉gson有关类型的更多信息。序列化时,类型也需要序列化。因此,Jacob G.的第一条评论建议您需要类型字段:
RuntimeTypeAdapterFactory.of(Class<T> baseType, String typeFieldName)
州的文档:
使用typeFieldName作为类型字段名称,为baseType创建一个新的运行时类型适配器。类型字段名称区分大小写。
将其添加到您的ParentBean
:
// Init it for serializing
// You used values like 'bean1' & 'bean2' but using class name is more generic
protected String type = getClass().getName();
根据上述bean类型名称的更改,相应地更改了RuntimeTypeAdapterFactory
的构建:
RuntimeTypeAdapterFactory<ParentBean> runtimeTypeAdapterFactory =
RuntimeTypeAdapterFactory
.of(ParentBean.class, "type") // typeFieldName
.registerSubtype(Bean1.class, Bean1.class.getName())
.registerSubtype(Bean2.class, Bean2.class.getName());
最后 - 当取消serailizing时 - Json文件还需要从字段type
序列化的类型信息,因此也要将两个bean Json添加到正确的包名称中:
"type":"org.example.gson.runtime.Bean1",
和
"type":"org.example.gson.runtime.Bean2",
答案 1 :(得分:1)
您不需要向bean显式添加类型字段。正如pirho建议的那样,您需要在json字符串中包含type字段。如果您是手工制作,则只需添加类型字段,例如
{
"type":"bean1",
"key1":"value1",
"key2":"value2",
"key3":"value33"
}
大概,您也在序列化对象,并且要实现该目标,您需要在序列化期间指定基类。
正如swankjesse指出的那样
https://github.com/google/gson/issues/712
尝试替换此:
final String jsonStr = mGson.toJson(new Child());
与此:
final String jsonStr = mGson.toJson(new Child(), Base.class);
然后,当您序列化类型时,输出json将为
{
"type":"bean1",
"key1":"value1",
"key2":"value2",
"key3":"value33"
}
这样,您的bean可以保持纯净,而无需知道它们提供了一些要用于序列化的类型密钥。