使用generics与GSON

我正在使用GSON将JSON解码为类型为T的对象,例如

public T decode(String json) { Gson gson = new Gson(); return gson.fromJson(json, new TypeToken() {}.getType()); } 

然而,这会返回一个例外 –

java.lang.AssertionError:意外类型。 期望的一个:java.lang.reflect.ParameterizedType,java.lang.reflect.GenericArrayType,但得到:sun.reflect.generics.reflectiveObjects.TypeVariableImpl,用于类型标记:T

我认为通过使用TypeToken我避免了类型擦除。

我错了吗?

谢谢

首先,我没有看到像这样包装Gson是多么有用。

至于您的问题,有关generics类型T本身的信息在运行时期间不可用。 它已被删除。 它仅在编译期间可用。 您希望使用实际类型对其进行参数化,而不是像new TypeToken>

由于Java中缺少具体的generics(不可能做T t = new T() ),Gson本身被迫使用TypeToken方法,如你所见。 否则Gson会以更优雅的方式完成它。

为了能够传递实际的类型,你需要重新发明与TypeToken已经做的相同的事情。 这没有任何意义:)只是重复使用它或只是直接使用Gson而不将它包装在这样的辅助类中。

我认为第一个答案并没有指出实际的解决方案:你还必须和T一起传递Class实例,如下所示:

 public T decode(String json, Class cls) { Gson gson = new Gson(); return gson.fromJson(json, cls); } 

这是因为’T’这里是VARIABLE类型,而不是类型引用; 并且仅由编译器用于添加隐式转换并validation类型兼容性。 但如果你通过实际课程,它可以使用; 和编译器将检查类型兼容性,以减少不匹配的可能性。

或者你可以接受TypeToken并传递它; 但是TypeToken必须用实数类型构造,而不是类型变量; 类型变量在这里用处不大。 但是如果你想要包装东西,你不希望调用者使用TypeToken(这是一种Gson类型)。

相同的包装机制可以与你提到的像Jackson这样的其他lib一起使用。

我的解决方案是使用json解析器并将其分解成碎片

 public static  PushObj fromJSON(String json, Class classType) { JsonObject jObj = new JsonParser().parse(json).getAsJsonObject(); String type = jObj.get("type").getAsString(); JsonObject job = jObj.get("object").getAsJsonObject(); TT obj = new Gson().fromJson(job, classType); return new PushObj(type, obj); } 

对象结构的位置是:{String:Type,Generic:Object}

变量是:jObj是传入的字符串的JSONObject,而job是通用对象的JSONObject

所以我使用json解析器单独获取类型,并使用对象的reflection。