65

我在我的 Android 应用程序(使用 Gson 库)中实现 Json 反序列化时遇到了一些问题

我做了这样的课

public class MyJson<T>{
    public List<T> posts;
}

反序列化调用是:

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);
  ...
  }
}

问题是调用后的 result.posts 列表包含一个 LinkedTreeMap 对象数组(具有正确的值,所以问题是反序列化)而不是 MyJson 对象。当我使用 MyObject 而不是 T 时,一切都运行良好并且 MyObject 是正确的。

那么有什么方法可以在不创建自定义反序列化器的情况下实现反序列化调用?

4

6 回答 6

49

您必须T在反序列化时指定类型。如果不知道要实例化什么,您List将如何创建?它不可能永远停留。因此,您可以将类型作为参数提供。postsGsonTypeTTClass

现在假设,您将反序列化的类型posts为(为简单起见,我还添加了一个参数;您将像以前一样从您的文件中读取):StringMyJson<String>String jsonreader

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;
}

类似地,反序列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;
}

我假设MyJson<T>我的例子是

public class MyJson<T> {

    public List<T> posts;

    public List<T> getPosts() {
        return posts;
    }
}

因此,如果您正在寻找反序列化 aList<MyObject>您将调用该方法为

// assuming no Void parameters were required
MyJson<MyObject> myJson = doInBackground(MyObject.class);
于 2013-08-23T07:57:00.167 回答
24

你有没有尝试过?

gson.create().fromJson(reader, MyJson.class);

编辑

阅读这篇文章后,您似乎使用的Type是正确的。我相信你的问题是使用T. 您必须记住,Java 有类型擦除。这意味着在运行时所有实例T都被替换为Object. 因此,在运行时您传递的 GSON 确实是MyJson<Object>. 如果你用一个具体的类来代替<T>我相信它会起作用。

Google Gson - 反序列化列表<class> 对象?(通用类型)

于 2013-08-23T07:41:42.787 回答
5

所以上面的答案对我不起作用,经过反复试验,我的代码就是这样结束的:

public class AbstractListResponse<T> {
    private List<T> result;

    public List<T> getResult() {
        return this.result;
    }
}

这里重要的部分是方法签名,包括左边的'<T>'。

protected <T> AbstractListResponse<T> parseAbstractResponse(String json, TypeToken type) {
    return new GsonBuilder()
            .create()
            .fromJson(json, type.getType());
}

调用 Gson 时,该方法接收到泛型对象的 TypeToken。

TypeToken<AbstractListResponse<MyDTO>> typeToken = new TypeToken<AbstractListResponse<MyDTO>>() {};
AbstractListResponse<MyDTO> responseBase = parseAbstractResponse(json, typeToken);

最后TypeToken 可以使用MyDTO,甚至是一个简单的对象,就可以使用MyDTO。

于 2016-11-16T21:46:55.513 回答
2

对于像我一样在 Kotlin 中苦苦挣扎的人,我已经找到了这种工作方式

val type = object : TypeToken<MyJson<MyObject>>() { }.type
val response = gson.fromJson<MyJson<MyObject>>(reader, type)

请注意,调用泛型函数需要在函数名称之后的调用站点的类型参数(参见此处

于 2018-12-15T20:00:43.060 回答
1

如果您使用的是gson 2.8.0或更高版本,可以使用以下方法TypeToken#getParametized((Type rawType, Type... typeArguments))

例子:

protected MyJson<T> doInBackground(Class<T> type, String json, Void... params) {

    GsonBuilder gson = new GsonBuilder();
    Type collectionType = TypeToken.getParameterized(MyJson.class, type).getType();

    MyJson<T> myJson = gson.create().fromJson(json, collectionType);

    System.out.println(myJson.getPosts()); // [true, false]
    return myJson;
}

我相信这将适用于您的情况。

归功于这个答案

于 2020-10-26T17:32:34.003 回答
1

我使用上面的答案在 Kotlin 中找出更通用的方法(但您可以在 java 中通过细微的调整重用)我有BaseDB<T>哪些加载Table<T>,而表有一个List<T>

fun parse(jsonString: String): Table<T> {
    //this gets the class for the type T
    val classT: Class<*> = (javaClass
        .genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<*>
    val type = TypeToken.getParameterized(Table::class.java, classT).type
    return GsonHelper.gson.fromJson<Table<T>>(jsonString, type)
}
于 2021-02-18T14:58:21.800 回答