java 在 GSON 中使用泛型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4226738/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using generics with GSON
提问by christophmccann
I am using GSON to decode JSON into an object of type T e.g.
我正在使用 GSON 将 JSON 解码为 T 类型的对象,例如
public T decode(String json) {
Gson gson = new Gson();
return gson.fromJson(json, new TypeToken<T>() {}.getType());
}
This however returns an exception -
然而,这会返回一个异常 -
java.lang.AssertionError: Unexpected type. Expected one of: java.lang.reflect.ParameterizedType, java.lang.reflect.GenericArrayType, but got: sun.reflect.generics.reflectiveObjects.TypeVariableImpl, for type token: T
java.lang.AssertionError: 意外类型。预期之一:java.lang.reflect.ParameterizedType、java.lang.reflect.GenericArrayType,但得到:sun.reflect.generics.reflectiveObjects.TypeVariableImpl,对于类型标记:T
I thought that by using TypeToken I avoided Type Erasure.
我认为通过使用 TypeToken 我避免了类型擦除。
Am I wrong?
我错了吗?
Thanks
谢谢
采纳答案by BalusC
First of all, I fail to see how it's useful to wrap Gson like that.
首先,我看不出像这样包装 Gson 有什么用。
As to your problem, the information about generic type T
itself is not available during runtime. It's been erased. It's only available during compile time. You want to parameterize it with the actual type instead like new TypeToken<List<String>>
.
至于你的问题,关于泛型T
本身的信息在运行时是不可用的。它被抹掉了。它仅在编译时可用。您想使用实际类型对其进行参数化,而不是像new TypeToken<List<String>>
.
Due to lack of reified Generics in Java (it isn't possible to do a T t = new T()
), Gson itself is forced to use the TypeToken
approach, as you see. Otherwise Gson would have done it in a much more elegant manner.
由于 Java 中缺乏具体化的泛型(不可能做 a T t = new T()
)TypeToken
,正如您所见,Gson 本身被迫使用该方法。否则 Gson 会以更优雅的方式完成它。
In order to be able to pass the actual type around, you've to reinvent the same thing as TypeToken
is already doing. And this makes no sense :) Just reuse it or just use Gson straight without wrapping it in some helper class like that.
为了能够传递实际类型,您必须重新发明TypeToken
已经在做的事情。这没有任何意义:) 只需重用它或直接使用 Gson 而不将其包装在类似的帮助类中。
回答by StaxMan
I think the first answer is not pointing out the actual solution: you MUST also pass Class instance along with T, like so:
我认为第一个答案并没有指出实际的解决方案:您还必须将 Class 实例与 T 一起传递,如下所示:
public T decode(String json, Class<T> cls) {
Gson gson = new Gson();
return gson.fromJson(json, cls);
}
This is because 'T' here is a type VARIABLE, not a type reference; and only used by compiler to add implicit casts and verify type compatibility. But if you pass actual class it can be used; and compiler will check type compatibility to reduce chance of mismatch.
这是因为这里的 'T' 是一个类型 VARIABLE,而不是一个类型引用;并且仅由编译器用于添加隐式强制转换和验证类型兼容性。但是,如果您通过实际课程,则可以使用它;并且编译器将检查类型兼容性以减少不匹配的机会。
Alternatively you could take in TypeToken and pass it; but TypeToken must be constructed with real type, not a type variable; type variable is of little use here. But if you do want to wrap things you wouldn't want caller to use TypeToken (which is a Gson type).
或者,您可以接收 TypeToken 并传递它;但 TypeToken 必须用真实类型构造,而不是类型变量;类型变量在这里用处不大。但是如果你确实想要包装东西,你不希望调用者使用 TypeToken(这是一种 Gson 类型)。
Same wrapping mechanism would work with other libs like Hymanson, which you mentioned.
相同的包装机制可以与您提到的 Hymanson 等其他库一起使用。
回答by tommyz87
My solution to this was to use the json parser and break it into pieces
我对此的解决方案是使用 json 解析器并将其分成几部分
public static <TT> PushObj<TT> fromJSON(String json, Class<TT> 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<TT>(type, obj);
}
Where the object structure is: {String:Type, Generic:Object}
其中对象结构是:{String:Type, Generic:Object}
And the variables are: jObj is the JSONObject of the string passed in and job is the JSONObject of the generic object
变量是:jObj 是传入字符串的 JSONObject,job 是通用对象的 JSONObject
So i used the json parser to get the type separately, and reflection for the object.
所以我使用json解析器分别获取类型和对象的反射。