使用GSON反序列化泛型类型时遇到麻烦

问题描述

我有一组代表我的数据库对象的4个类(数据库当前仅是一个ArrayList)。
我正在使用GSON将这些对象存储在.txt文件中。
一个名为Storage的类负责将这些对象读取和写入这些.txt文件
这是我的问题: 我有一个通用对象T extends MyInterface。该对象代表4个数据库类。 我将T放在了Storage方法中,所以我可以对任何一个数据库对象只使用这一类。 这是代码

public class Storage<T extends MyInterface> {

     Gson GSON = new Gson();

     public ArrayList<T> readAll() {
         String objectsJSON = TextFileHandler.readFromFile(fileStorageLocation); // This works
         System.out.println(objectsJSON);   // This also works  (prints out correctly)
         Type collectionType = new Typetoken<ArrayList<T>>() {}.getType();  
         return GSON.fromJson(objectsJSON,collectionType);     // This fails
     }

}

我收到以下异常:

java.lang.classCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to 
interfaces.MyInterface

你们知道这可能是什么吗?

解决方法

匿名TypeToken子类型的全部要点是它们是在编译时定义的,因此可以保存通用类型信息。您需要做一些事情以使令牌信息动态可用。 This approach可能会起作用:

private final TypeToken<ArrayList<T>> targetType;

public Storage(Class<T> dataType) {
    targetType = new TypeToken<ArrayList<T>>(){}
        .where(new TypeParameter<T>(){},dataType);
}

public List<T> readAll() { // avoid using concrete ArrayList in public API;
                           // not a bad idea to change it in the other locations
    ...
    return GSON.fromJson(objectsJson,targetType);
}
,

您应该使用接口List,而不是ArrayList

public List<T> readAll() {
     String objectsJSON = TextFileHandler.readFromFile(fileStorageLocation);
     System.out.println(objectsJSON);
     Type collectionType = new TypeToken<List<T>>() {}.getType();  
     return GSON.fromJson(objectsJSON,collectionType);
 }

如果这不起作用,请检查objectJSON是否正确(JSON格式)。

,

对于任何可能正在寻找答案的人,这就是我为解决此问题所做的工作:

问题在于GSON不知道要实例化哪个类,因为我的Storage<T>用于几个不同的实体。我不得不以某种方式告诉它,每个Storage<T>实例都使用哪个特定的实体类。 我遇到的错误是这样的:

Cannot cast LinkedTreeMap to MyInterface.
因为在运行时,Storage不知道要实例化哪个类。

我正在做一个常规的Java项目,所以我下载了Guava.jar并将其添加到我的项目中: http://search.maven.org/remotecontent?filepath=com/google/guava/guava/23.0/guava-23.0.jar

我修改了通用类Storage<T>的构造函数,以使用Class<T> dataType参数,以便它可以在运行时知道其用于哪个类。 我还添加了一个私有字段TypeToken<List<T>>,以便它可以存储有关要反序列化的类的信息。

基本上,我所做的只是这个:

import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import com.google.gson.*;

public class Storage<T extends MyInterface> {

     // This was used so the Storage objects knows which dataType it's associated to 
     // Because T is deleted at runtime,so you can't use that.
     private TypeToken<List<T>> targetDataType;

     // I changed the constructor to take in 1 bonus argument
     public Storage(Class<T> dataType) {
          targetDataType = new TypeToken<List<T>>() {}
                        .where(new TypeParameter<T>() {},dataType);            
     }

     public List<T> deserialize() {
         // Read JSON data into a <jsonString> variable
    
         Gson GSON = new Gson();
         return GSON.fromJson(jsonString,targetDataType.getType());
     }
}