使用GSON反序列化通用类型

Viz*_*har 46 java android json gson deserialization

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

我上过这样的课

public class MyJson<T>{
    public List<T> posts;
}
Run Code Online (Sandbox Code Playgroud)

反序列化调用是:

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);
  ...
  }
}
Run Code Online (Sandbox Code Playgroud)

问题是调用后的result.posts列表包含一个LinkedTreeMap对象数组(具有正确的值,因此问题是反序列化)而不是MyJson对象.当我使用MyObject而不是T时,一切正常,MyObject正确.

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

Rav*_*yal 31

您必须指定T反序列化时的类型.如何将你Listposts得到,如果创建了Gson不知道什么Type实例?它不能T永远存在.因此,您可以将类型T作为Class参数提供.

现在假设,类型postsString你会反序列化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;
}
Run Code Online (Sandbox Code Playgroud)

类似地,反序列化MyJsonBoolean对象

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;
}
Run Code Online (Sandbox Code Playgroud)

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

public class MyJson<T> {

    public List<T> posts;

    public List<T> getPosts() {
        return posts;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

// assuming no Void parameters were required
MyJson<MyObject> myJson = doInBackground(MyObject.class);
Run Code Online (Sandbox Code Playgroud)

  • 不,它不会因为运行时的类型擦除.因此,无论您将哪种类型作为参数传递,您的函数都将始终返回`MyJson <Object>`. (5认同)
  • 你的代码中使用的"Class <T> type"究竟在哪里? (3认同)

Joh*_*n B 24

你有没有尝试过?

gson.create().fromJson(reader, MyJson.class);
Run Code Online (Sandbox Code Playgroud)

编辑

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

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


Dav*_*ves 7

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

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

    public List<T> getResult() {
        return this.result;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

TypeToken<AbstractListResponse<MyDTO>> typeToken = new TypeToken<AbstractListResponse<MyDTO>>() {};
AbstractListResponse<MyDTO> responseBase = parseAbstractResponse(json, typeToken);
Run Code Online (Sandbox Code Playgroud)

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