首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法用RuntimeTypeAdapterFactory反序列化,“未定义名为类型的字段”

无法用RuntimeTypeAdapterFactory反序列化,“未定义名为类型的字段”
EN

Stack Overflow用户
提问于 2018-02-18 18:25:41
回答 2查看 6.4K关注 0票数 6

我试图通过Gson框架学习java bean的继承和反序列化的概念。有关java类和json文件的详细信息如下所示。

ParentBean.java

代码语言:javascript
复制
public class ParentBean {

    protected String key1;
    protected String key2;

    public ParentBean(String key1, String key2) {
        super();
        this.key1 = key1;
        this.key2 = key2;
    }

}

Bean1.java

代码语言:javascript
复制
public class Bean1 extends ParentBean {

    private String key3;

    public Bean1(String key1, String key2, String key3) {
        super(key1, key2);
        this.key3 = key3;
    }

}

Bean2.java

代码语言:javascript
复制
public class Bean2 extends ParentBean {

    private String key4;

    public Bean2(String key1, String key2, String key4) {
        super(key1, key2);
        this.key4 = key4;
    }

}

bean1.json

代码语言:javascript
复制
{
    "key1":"value1",
    "key2":"value2",
    "key3":"value33"
}

bean2.json

代码语言:javascript
复制
{ 
    "key1":"value1", 
    "key2":"value2", 
    "key4":"value43"
}

为了探索有关继承和反序列化的内容,我使用了以下代码:

Usage.java

代码语言:javascript
复制
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");
            } 
    }

}

我得到一个错误堆栈,如下所示:

代码语言:javascript
复制
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)

为了寻找解决方案,我遇到了堆栈溢出讨论。不幸的是,讨论的主题是create()方法。错误堆栈说问题出在第23行,这一行包含fromJson()方法。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-02-19 12:20:02

您需要告诉葛森更多关于类型的信息。在序列化时,还需要序列化类型。因此,正如Jacob G.的第一个评论所建议的那样,您需要类型字段:

用于RuntimeTypeAdapterFactory.of(Class<T> baseType, String typeFieldName)的Docs声明:

使用baseType创建一个新的运行时类型适配器,使用typeFieldName作为类型字段名。类型字段名区分大小写。

将其添加到您的ParentBean

代码语言:javascript
复制
// Init it for serializing 
// You used values like 'bean1' & 'bean2' but using class name is more generic
protected String type = getClass().getName(); 

根据以上更改,bean类型名称的更改相应地更改了RuntimeTypeAdapterFactory的构建:

代码语言:javascript
复制
RuntimeTypeAdapterFactory<ParentBean> runtimeTypeAdapterFactory = 
    RuntimeTypeAdapterFactory
        .of(ParentBean.class, "type") // typeFieldName
        .registerSubtype(Bean1.class, Bean1.class.getName())
        .registerSubtype(Bean2.class, Bean2.class.getName());

最后,当去服务器化时,Json文件还需要类型信息,这些信息将从type字段序列化,因此,也可以在两个bean中添加类型信息,并具有正确的包名:

代码语言:javascript
复制
"type":"org.example.gson.runtime.Bean1",

代码语言:javascript
复制
"type":"org.example.gson.runtime.Bean2",
票数 4
EN

Stack Overflow用户

发布于 2019-03-08 18:33:09

您不需要显式地向bean中添加类型字段。正如pirho所建议的,您需要在json字符串中包含类型字段。如果您是手工制作的,只需添加类型字段。

代码语言:javascript
复制
{
    "type":"bean1",
    "key1":"value1",
    "key2":"value2",
    "key3":"value33"
}

想必,您也在序列化对象,为了实现这一点,您需要在序列化期间指定基类。

正如斯旺基塞指出的那样

https://github.com/google/gson/issues/712

试着替换这个:

代码语言:javascript
复制
    final String jsonStr = mGson.toJson(new Child());

在这方面:

代码语言:javascript
复制
    final String jsonStr = mGson.toJson(new Child(), Base.class);

然后,当您序列化类型时,您的输出json将是

代码语言:javascript
复制
{
    "type":"bean1",
    "key1":"value1",
    "key2":"value2",
    "key3":"value33"
}

这样,您的bean就可以保持纯净,而不知道它们提供了用于序列化的某种类型键。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48855124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档