Java 使用 GSON 反序列化泛型类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18397342/
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
Deserializing Generic Types with GSON
提问by VizGhar
I have some problems with implementation of Json Deserialization in my Android application (with Gson library)
我在我的 Android 应用程序中实现 Json 反序列化有一些问题(使用 Gson 库)
I've made class like this
我上过这样的课
public class MyJson<T>{
public List<T> posts;
}
And Deserialization call is:
反序列化调用是:
public class JsonDownloader<T> extends AsyncTask<Void, Void, MyJson<T>> {
...
protected MyJson<T> doInBackground(Void... params) {
...
Reader reader = new InputStreamReader(content);
GsonBuilder gson = new GsonBuilder();
Type collectionType = new TypeToken<MyJson<T>>() {}.getType();
result = gson.create().fromJson(reader, collectionType);
...
}
}
Problem is that result.posts list after call holds one Array of LinkedTreeMap Objects(with correct values so problem is Deserialization) instead of MyJson Objects. When I use MyObject instead of T everything is running fine and MyObject is correct.
问题是调用后的 result.posts 列表包含一个 LinkedTreeMap 对象数组(具有正确的值,因此问题是反序列化)而不是 MyJson 对象。当我使用 MyObject 而不是 T 时,一切都运行良好并且 MyObject 是正确的。
So is there any way to implement deserialization call without creating custom deserializer?
那么有没有什么方法可以在不创建自定义反序列化器的情况下实现反序列化调用呢?
采纳答案by Ravi Thapliyal
You have to specify the type of T
at the time of deserialization. How would your List
of posts
get created if Gson
didn't know what Type
to instantiate? It can't stay T
forever. So, you would provide the type T
as a Class
parameter.
您必须T
在反序列化时指定类型。如何将你List
的posts
得到建立,如果Gson
不知道什么是Type
实例化?它不能T
永远停留。因此,您将提供类型T
作为Class
参数。
Now assuming, the type of posts
was String
you would deserialize MyJson<String>
as (I've also added a String json
parameter for simplicity; you would read from your reader
as before):
现在假设,类型posts
是String
你会反序列化MyJson<String>
的(我还添加了一个String json
用于简单的参数,你会从你读reader
如前):
doInBackground(String.class, "{posts: [\"article 1\", \"article 2\"]}");
protected MyJson<T> doInBackground(Class<T> type, String json, Void... params) {
GsonBuilder gson = new GsonBuilder();
Type collectionType = new TypeToken<MyJson<T>>(){}.getType();
MyJson<T> myJson = gson.create().fromJson(json, collectionType);
System.out.println(myJson.getPosts()); // ["article 1", "article 2"]
return myJson;
}
Similarly, to deserialize a MyJson
of Boolean
objects
类似地,反序列化MyJson
的Boolean
对象
doInBackground(Boolean.class, "{posts: [true, false]}");
protected MyJson<T> doInBackground(Class<T> type, String json, Void... params) {
GsonBuilder gson = new GsonBuilder();
Type collectionType = new TypeToken<MyJson<T>>(){}.getType();
MyJson<T> myJson = gson.create().fromJson(json, collectionType);
System.out.println(myJson.getPosts()); // [true, false]
return myJson;
}
I've assumed MyJson<T>
for my examples to be as
我假设MyJson<T>
我的例子是
public class MyJson<T> {
public List<T> posts;
public List<T> getPosts() {
return posts;
}
}
So, if you were looking for to deserialize a List<MyObject>
you would invoke the method as
因此,如果您正在寻找反序列化 aList<MyObject>
您可以调用该方法
// assuming no Void parameters were required
MyJson<MyObject> myJson = doInBackground(MyObject.class);
回答by John B
Have you tried?
你有没有尝试过?
gson.create().fromJson(reader, MyJson.class);
EDIT
编辑
After reading thispost it seems that you use of Type
is correct. I believe your issue is the use of T
. You must remember that with Java there is type-erasure. This means that at runtime all instances of T
are replaced with Object
. Therefore at runtime what you are passing GSON is really MyJson<Object>
. If you tried this with a concrete class in place of <T>
I believe it would work.
阅读这篇文章后,您似乎使用的Type
是正确的。我相信你的问题是使用T
. 您必须记住,在 Java 中存在类型擦除。这意味着在运行时所有实例T
都被替换为Object
. 因此,在运行时您传递 GSON 的内容实际上是MyJson<Object>
. 如果你用一个具体的类来代替<T>
我相信它会起作用。
Google Gson - deserialize list<class> object? (generic type)
回答by Davi Alves
So the above answer didn't work for me, after trial and error that's how my code ended:
所以上面的答案对我不起作用,经过反复试验,我的代码就是这样结束的:
public class AbstractListResponse<T> {
private List<T> result;
public List<T> getResult() {
return this.result;
}
}
The important part here is the method signature, including the '< T >' on the left.
这里的重要部分是方法签名,包括左侧的“< T >”。
protected <T> AbstractListResponse<T> parseAbstractResponse(String json, TypeToken type) {
return new GsonBuilder()
.create()
.fromJson(json, type.getType());
}
When calling Gson, the method receives the TypeToken of the generic object.
调用 Gson 时,该方法接收泛型对象的 TypeToken。
TypeToken<AbstractListResponse<MyDTO>> typeToken = new TypeToken<AbstractListResponse<MyDTO>>() {};
AbstractListResponse<MyDTO> responseBase = parseAbstractResponse(json, typeToken);
And finally the TypeToken can use MyDTO, or even a simple object, just MyDTO.
最后,TypeToken 可以使用 MyDTO,甚至是一个简单的对象,只是 MyDTO。
回答by tudor
For anyone struggling with Kotlin like I did, I've found this way to work
对于像我一样在 Kotlin 上挣扎的人,我找到了这种工作方式
val type = object : TypeToken<MyJson<MyObject>>() { }.type
val response = gson.fromJson<MyJson<MyObject>>(reader, type)
Note that calling a generic function requires the type arguments at the call site after the name of the function (seen here)
请注意,调用泛型函数需要在函数名称之后的调用站点上使用类型参数(参见此处)