使用GSON反序列化泛型类型

siotufzp  于 2022-11-06  发布在  其他
关注(0)|答案(6)|浏览(302)

我在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是正确的。
那么,有没有办法在不创建自定义反序列化程序的情况下实现反序列化调用呢?

xggvc2p6

xggvc2p61#

你必须在反序列化的时候指定T的类型。如果Gson不知道示例化什么Type,你将如何创建postsList?它不能永远保持T。所以,你将提供T类型作为Class参数。
现在,假设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;
}

类似地,要反序列化Boolean对象的MyJson

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

因此,如果您要寻找来还原序列化List<MyObject>,您应该以下列方式叫用方法

// assuming no Void parameters were required
MyJson<MyObject> myJson = doInBackground(MyObject.class);
xqkwcwgp

xqkwcwgp2#

你试过吗?

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

编辑

在阅读this的帖子之后,似乎你对Type的使用是正确的。我相信你的问题是T的使用。你必须记住,Java有类型擦除。这意味着在运行时,所有T的示例都被Object替换。因此,在运行时,你传递给GSON的实际上是MyJson<Object>。如果你尝试用一个具体的类来代替<T>,我相信它会起作用。
Google Gson - deserialize list object? (generic type)

apeeds0o

apeeds0o3#

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

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。

vcudknz3

vcudknz34#

对于任何像我一样和Kotlin斗争的人来说,我找到了这样的工作方式

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

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

83qze16e

83qze16e5#

如果您使用的是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;
}

我相信这对你的情况会起作用。
感谢this answer

9jyewag0

9jyewag06#

我用上面的答案在Kotlin中找到了更通用的方法(但你可以在java中稍作调整后重用)我有BaseDB<T>,它加载Table<T>,而Table有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)
}

相关问题