使用GSON反序列化通用类型

时间:2013-08-23 07:36:23

标签: java android json deserialization gson

我的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是正确的。

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

6 个答案:

答案 0 :(得分:26)

您必须在反序列化时指定T的类型。如果List不知道实例化posts是什么,那么Gson Type如何创建?它不能永远留在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;
}

同样,要反序列化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;
}

我认为我的例子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);

答案 1 :(得分:24)

你试过吗?

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

修改

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

Google Gson - deserialize list<class> object? (generic type)

答案 2 :(得分:3)

所以上述答案对我来说并不适合我,经过反复试验后我的代码如何结束:

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

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

这里的重要部分是方法签名,包括&#39;&lt; T&gt;&#39;在左边。

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。

答案 3 :(得分: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;
}

我相信这会在您的情况下起作用。

贷记this answer

答案 4 :(得分:1)

我用上面的答案在 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)
}

答案 5 :(得分:0)

对于像我一样在Kotlin上挣扎的任何人,我都找到了这种工作方式

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

请注意,调用泛型函数需要在函数名称(见here之后)的调用位置输入类型参数