无法使用 RuntimeTypeAdapterFactory 反序列化,“未定义名为 type 的字段”

Nit*_*hin 6 java json gson

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

父Bean.java

public class ParentBean {

    protected String key1;
    protected String key2;

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

}
Run Code Online (Sandbox Code Playgroud)

Bean1.java

public class Bean1 extends ParentBean {

    private String key3;

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

}
Run Code Online (Sandbox Code Playgroud)

Bean2.java

public class Bean2 extends ParentBean {

    private String key4;

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

}
Run Code Online (Sandbox Code Playgroud)

bean1.json

{
    "key1":"value1",
    "key2":"value2",
    "key3":"value33"
}
Run Code Online (Sandbox Code Playgroud)

bean2.json

{ 
    "key1":"value1", 
    "key2":"value2", 
    "key4":"value43"
}
Run Code Online (Sandbox Code Playgroud)

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

用法.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");
            } 
    }

}
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

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

pir*_*rho 5

您需要告诉有关类型的更多信息。序列化时,类型也需要序列化。因此,正如 Jacob G. 的第一条评论所示,您需要类型字段:

各州的文件RuntimeTypeAdapterFactory.of(Class<T> baseType, String typeFieldName)

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

将其添加到您的ParentBean

// Init it for serializing 
// You used values like 'bean1' & 'bean2' but using class name is more generic
protected String type = getClass().getName(); 
Run Code Online (Sandbox Code Playgroud)

根据上述 bean 类型名称的变化,相应地更改构建RuntimeTypeAdapterFactory

RuntimeTypeAdapterFactory<ParentBean> runtimeTypeAdapterFactory = 
    RuntimeTypeAdapterFactory
        .of(ParentBean.class, "type") // typeFieldName
        .registerSubtype(Bean1.class, Bean1.class.getName())
        .registerSubtype(Bean2.class, Bean2.class.getName());
Run Code Online (Sandbox Code Playgroud)

最后 - 当反序列化时 - Json 文件还需要将从字段序列化的类型信息type,因此也将其添加到具有正确包名称的两个 bean Json 中:

"type":"org.example.gson.runtime.Bean1",
Run Code Online (Sandbox Code Playgroud)

"type":"org.example.gson.runtime.Bean2",
Run Code Online (Sandbox Code Playgroud)