在反序列化时,Gson无法“理解”泛型类型

时间:2013-04-07 17:08:45

标签: java generics deserialization gson

我创建了这个内存类:

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

感谢。

1 个答案:

答案 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));
}