我创建了这个内存类:
public class Memory {
private final Hashtable<String, String> data;
private final Gson gson;
public Memory() {
this.data = new Hashtable<String, String>();
this.gson = new Gson();
}
public <T> void set(String key, List<T> value) {
this.data.put(key, this.gson.toJson(value));
}
public <T> List<T> get(String key, Class<T> cls) {
Type type = new TypeToken<List<T>>() {}.getType();
return this.gson.fromJson(this.data.get(key), type);
}
}
我可以在json中存储泛型类型的列表,然后反序列化它们
但是当我尝试使用它时,例如:
public class User {
private int id;
private String username;
public User() { }
public User(int id, String username) {
this.id = id;
this.username = username;
}
}
Memory memory = new Memory();
List<User> users = new ArrayList<User>();
// add users
memory.set("users", users);
// now get the users back
List<User> copy = memory.get("users", User.class);
Gson返回StringMap的ArrayList而不是Users 这显然与我正在使用的泛型有关,但有没有办法绕过它?
感谢。
答案 0 :(得分:2)
Java Generics允许的明显不一致性凸显了真正的失败,其中List<User>
最终被com.google.gson.internal.StringMap
的实例填充!但那是另一个话题。
当前的问题是您没有正确使用类型令牌类。令牌的关键在于您必须使用具体类型扩展类 - 但是您使用在编译时验证的方法级泛型参数来实例化该类,然后 擦除 (并且随后在运行时不可用)。但类型令牌的全部意义在于 保留 通用信息,因此该模型已被烧毁。
老实说,这是令牌执行失败的原因 - 如果您将构造函数代码与TypeReference
implementation of Jackson进行比较,您会看到Jackson实际验证了具体参数是否可用。
31 protected TypeReference()
32 {
33 Type superClass = getClass().getGenericSuperclass();
34 if (superClass instanceof Class<?>) { // sanity check, should never happen
35 throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
36 }
45 }
最简单的解决方案是简单地将构造类型(令牌)作为调用者的责任,并将其与您希望存储和/或检索的数据一起传递。
public <T> List<T> get(String key, Type type) {
return this.gson.fromJson(this.data.get(key), type);
}
public <T> void set(String key, List<T> value, Type type) {
this.data.put(key, this.gson.toJson(value, type));
}