使用 GSON 反序列化泛型类型时遇到问题
Trouble deserializing generic types using GSON
我有一组 4 个 classes 代表我的数据库对象(数据库目前只是一个 ArrayList)。
我正在使用 GSON 将这些对象存储在 .txt 文件中。
名为 Storage
的单个 class 负责读取这些对象并将其写入那些 .txt 文件。
这是我的问题:
我有一个通用对象 T extends MyInterface
。该对象代表 4 个数据库 classes。
我将 T
放在 Storage
方法中,因此我可以将这个 class 用于任何数据库对象。
这是代码:
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 不知道要实例化哪个 class,因为我的 Storage<T>
用于几个不同的实体。我不得不以某种方式告诉它,Storage<T>
的每个实例都用于哪个特定实体 class。
我得到的错误是这样的:
Cannot cast LinkedTreeMap to MyInterface.
因为在运行时,Storage
不知道要实例化哪个 class。
我正在做一个常规的 Java 项目,所以我下载了 Guava.jar 并将其添加到我的项目中:
http://search.maven.org/remotecontent?filepath=com/google/guava/guava/23.0/guava-23.0.jar
我修改了我的通用 class Storage<T>
构造函数,以接收 Class<T> dataType
参数,以便它可以在运行时知道它被用于哪个 class。
我还添加了一个私有字段 TypeToken<List<T>>
,因此它可以存储有关 class 被反序列化的信息。
基本上,我所做的就是:
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());
}
}
我有一组 4 个 classes 代表我的数据库对象(数据库目前只是一个 ArrayList)。
我正在使用 GSON 将这些对象存储在 .txt 文件中。
名为 Storage
的单个 class 负责读取这些对象并将其写入那些 .txt 文件。
这是我的问题:
我有一个通用对象 T extends MyInterface
。该对象代表 4 个数据库 classes。
我将 T
放在 Storage
方法中,因此我可以将这个 class 用于任何数据库对象。
这是代码:
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 不知道要实例化哪个 class,因为我的 Storage<T>
用于几个不同的实体。我不得不以某种方式告诉它,Storage<T>
的每个实例都用于哪个特定实体 class。
我得到的错误是这样的:
Cannot cast LinkedTreeMap to MyInterface.
因为在运行时,Storage
不知道要实例化哪个 class。
我正在做一个常规的 Java 项目,所以我下载了 Guava.jar 并将其添加到我的项目中: http://search.maven.org/remotecontent?filepath=com/google/guava/guava/23.0/guava-23.0.jar
我修改了我的通用 class Storage<T>
构造函数,以接收 Class<T> dataType
参数,以便它可以在运行时知道它被用于哪个 class。
我还添加了一个私有字段 TypeToken<List<T>>
,因此它可以存储有关 class 被反序列化的信息。
基本上,我所做的就是:
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());
}
}