使用Gson反序列化List<T>对象?

531
我希望通过Google Gson传输一个列表对象,但我不知道如何反序列化泛型类型。
在查看this(BalusC的答案)后,我尝试了以下方法:
MyClass mc = new Gson().fromJson(result, new List<MyClass>() {}.getClass());

然后在Eclipse中,我收到了一个错误提示:"类型new List<MyClass>() {}必须实现继承的抽象方法..."如果我使用快速修复,我会得到超过20个方法桩的怪物。

我相信一定有更简单的解决方案,但是我似乎找不到!

现在我有这个:

Type listType = new TypeToken<List<MyClass>>() {}.getType();

MyClass mc = new Gson().fromJson(result, listType);

然而,在fromJson这一行,我遇到了以下异常:

java.lang.NullPointerException
at org.apache.harmony.luni.lang.reflect.ListOfTypes.length(ListOfTypes.java:47)
at org.apache.harmony.luni.lang.reflect.ImplForType.toString(ImplForType.java:83)
at java.lang.StringBuilder.append(StringBuilder.java:203)
at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:56)
at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:88)
at com.google.gson.JsonDeserializationVisitor.visitUsingCustomHandler(JsonDeserializationVisitor.java:76)
at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:106)
at com.google.gson.JsonDeserializationContextDefault.fromJsonArray(JsonDeserializationContextDefault.java:64)
at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:49)
at com.google.gson.Gson.fromJson(Gson.java:568)
at com.google.gson.Gson.fromJson(Gson.java:515)
at com.google.gson.Gson.fromJson(Gson.java:484)
at com.google.gson.Gson.fromJson(Gson.java:434)

我捕获了JsonParseExceptions,并且result不为null。

我使用调试器检查了listType,得到以下结果:

  • list Type
    • args = ListOfTypes
      • list = null
      • resolvedTypes = Type[ 1 ]
    • loader = PathClassLoader
    • ownerType0 = null
    • ownerTypeRes = null
    • rawType = Class (java.util.ArrayList)
    • rawTypeName = "java.util.ArrayList"

所以看起来getClass调用没有正常工作。有什么建议吗?

我在Gson用户指南上进行了检查。它提到了一个运行时异常,在将通用类型解析为Json时应该发生。我按照示例“错误”地执行了此操作(未在上面显示),但根本没有出现该异常。因此,我按照用户指南建议的更改了序列化。但是这并没有帮助。

编辑:

问题已解决,请参见我的下面的回答。


1
你指向的答案使用了 TokenType。你尝试过那种方式吗? - Nishant
刚刚得到了相同的提示作为答案。下次我会更仔细地看例子的。;) - jellyfish
你能否尝试在类型标记中实现列表?由于你的原始类型是数组列表,因此应该尝试使用数组列表。 - uncaught_exceptions
15个回答

1
请参考示例2,了解Gson中“Type”类的理解。
示例1:在此deserilizeResturant中,我们使用了Employee[]数组并获取了详细信息。
public static void deserializeResturant(){

       String empList ="[{\"name\":\"Ram\",\"empId\":1},{\"name\":\"Surya\",\"empId\":2},{\"name\":\"Prasants\",\"empId\":3}]";
       Gson gson = new Gson();
       Employee[] emp = gson.fromJson(empList, Employee[].class);
       int numberOfElementInJson = emp.length();
       System.out.println("Total JSON Elements" + numberOfElementInJson);
       for(Employee e: emp){
           System.out.println(e.getName());
           System.out.println(e.getEmpId());
       }
   }

例子2:
//Above deserilizeResturant used Employee[] array but what if we need to use List<Employee>
public static void deserializeResturantUsingList(){

    String empList ="[{\"name\":\"Ram\",\"empId\":1},{\"name\":\"Surya\",\"empId\":2},{\"name\":\"Prasants\",\"empId\":3}]";
    Gson gson = new Gson();

    // Additionally we need to se the Type then only it accepts List<Employee> which we sent here empTypeList
    Type empTypeList = new TypeToken<ArrayList<Employee>>(){}.getType();


    List<Employee> emp = gson.fromJson(empList, empTypeList);
    int numberOfElementInJson = emp.size();
    System.out.println("Total JSON Elements" + numberOfElementInJson);
    for(Employee e: emp){
        System.out.println(e.getName());
        System.out.println(e.getEmpId());
    }
}

1
使用 Kotlin,您可以为所有自定义可序列化类型获取通用的 MutableList 类型。
private fun <T : Serializable> getGenericList(
    sharedPreferences: SharedPreferences,
    key: String,
    clazz: KClass<T>
): List<T> {
    return sharedPreferences.let { prefs ->
        val data = prefs.getString(key, null)
        val type: Type = TypeToken.getParameterized(MutableList::class.java, clazz.java).type
        gson.fromJson(data, type) as MutableList<T>
    }
}

你可以调用这个函数。
getGenericList.(sharedPrefObj, sharedpref_key, GenericClass::class)

0

我为这个案例创建了GsonUtils库。我将其添加到Maven中央仓库。

Map<String, SimpleStructure> expected = new HashMap<>();
expected.put("foo", new SimpleStructure("peperoni"));

String json = GsonUtils.writeValue(expected);

Map<String, SimpleStructure> actual = GsonUtils.readMap(json, String.class, SimpleStructure.class);

0
在我的情况下,@uncaught_exceptions的答案不起作用,我必须使用而不是:
String jsonDuplicatedItems = request.getSession().getAttribute("jsonDuplicatedItems").toString();
List<Map.Entry<Product, Integer>> entries = gson.fromJson(jsonDuplicatedItems, List.class);

-1

我很喜欢kays1的回答,但是我无法实现它。所以我根据他的概念构建了自己的版本。

public class JsonListHelper{
    public static final <T> List<T> getList(String json) throws Exception {
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        Type typeOfList = new TypeToken<List<T>>(){}.getType();
        return gson.fromJson(json, typeOfList);
    }
}

使用方法:

List<MyClass> MyList= JsonListHelper.getList(jsonArrayString);

这肯定行不通,因为你试图在编译时使用T。这将有效地反序列化为一个StringMap列表,对吧? - JHH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接