1

我创建了这个内存类:

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。
这显然与我正在使用的泛型有关,但是有没有办法绕过它?

谢谢。

4

1 回答 1

2

Java 泛型允许的明显不一致突出了这里真正的失败,其中 aList<User>最终被com.google.gson.internal.StringMap!的实例填充。但这完全是另一个话题。

直接的问题是您没有正确使用类型令牌类。令牌的重点是您必须使用具体类型扩展类 - 但是您正在使用方法级别的泛型参数实例化该类,该参数在编译时验证然后被删除(随后在运行时不可用)。但是类型标记的全部意义在于保留通用信息,因此模型被炸毁了。

老实说,这是令牌实现的失败——如果您将构造函数代码与例如TypeReferenceJackson 的实现进行比较,您会看到 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));
}
于 2013-04-07T17:48:16.370 回答