谷歌Gson – 反序列化列表<class>对象? (通用型)

我想通过谷歌Gson传递一个列表对象,但我不知道如何反序列化genericstypes。

我看了这个 (BalusC的回答)之后试了一下:

MyClass mc = new Gson().fromJson(result, new List<MyClass>(){}.getClass()); 

但是后来我在eclipse中得到一个错误:“新的List(){}types必须实现inheritance的抽象方法…”,如果我使用快速修复,我会得到一个超过20个方法存根的怪物。

我很确定有一个更简单的解决scheme,但我似乎无法find它!

编辑:

我现在有

 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。

我用debugging器检查了listType,得到了以下结果:

  • 列表types
    • args = ListOfTypes
      • list = null
      • resolvedTypes =types[1]
    • loader = PathClassLoader
    • ownerType0 = null
    • ownerTypeRes = null
    • rawType = Class(java.util.ArrayList)
    • rawTypeName =“java.util.ArrayList”

所以看起来“getClass”调用没有正常工作。 有什么build议么…?

编辑2:我检查了Gson用户指南 。 它提到了在将一个genericstypesparsing为Json的过程中发生的运行时exception。 我做了“错误”(上面没有显示),就像在这个例子中一样,但没有得到那个例外。 所以我改变了序列化在用户指南build议。 虽然没有帮助。

编辑3:解决,看到我的答案在下面。

反序列化generics集合的方法:

 import java.lang.reflect.Type; import com.google.gson.reflect.TypeToken; ... Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType(); List<YourClass> yourClassList = new Gson().fromJson(jsonArray, listType); 

另一种方法是使用数组作为types,例如:

 MyClass[] mcArray = gson.fromJson(jsonString, MyClass[].class); 

这样,您可以避免使用Type对象带来的麻烦,如果您确实需要列表,则始终可以通过以下方式将数组转换为列表:

 List<MyClass> mcList = Arrays.asList(mcArray); 

恕我直言,这是更可读。

为了使它成为一个真正的列表(可以修改,请参阅Arrays.asList()限制),然后执行以下操作:

 List<MyClass> mcList = new ArrayList<>(Arrays.asList(mcArray)); 

对于那些不明确的typesinputbuild议,这是你想要的。

 import java.lang.reflect.Type; 

参考这篇文章。 Javatypes作为GSON的参数

我有更好的解决scheme。 这里是列表的包装类,所以包装器可以存储确切types的列表。

 public class ListOfJson<T> implements ParameterizedType { private Class<?> wrapped; public ListOfJson(Class<T> wrapper) { this.wrapped = wrapper; } @Override public Type[] getActualTypeArguments() { return new Type[] { wrapped }; } @Override public Type getRawType() { return List.class; } @Override public Type getOwnerType() { return null; } } 

然后,代码可以很简单:

 public static <T> List<T> toList(String json, Class<T> typeClass) { return sGson.fromJson(json, new ListOfJson<T>(typeClass)); } 

Wep,另一种达到相同结果的方式。 我们使用它来提高可读性。

而不是做这个难以阅读的句子:

 Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType(); List<YourClass> list = new Gson().fromJson(jsonArray, listType); 

创build一个扩展对象列表的空类:

 public class YourClassList extends ArrayList<YourClass> {} 

parsingJSON时使用它:

 List<YourClass> list = new Gson().fromJson(jsonArray, YourClassList.class); 
 public static final <T> List<T> getList(final Class<T[]> clazz, final String json) { final T[] jsonToObject = new Gson().fromJson(json, clazz); return Arrays.asList(jsonToObject); } 

例:

 getList(MyClass[].class, "[{...}]"); 

由于它回答了我原来的问题,我已经接受了doc_180的答案,但是如果有人再次遇到这个问题,我也会回答我的问题的后半部分:

我所描述的NullPointerError与List本身无关,只是内容!

“MyClass”类没有“no args”构造函数,也没有超类。 一旦我向MyClass及其超类添加了一个简单的“MyClass()”构造函数,一切正常,包括doc_180build议的List序列化和反序列化。

这是一个解决scheme,与dynamic定义的types一起工作。 诀窍是使用Array.newInstance()创build适当types的数组。

 public static <T> List<T> fromJsonList(String json, Class<T> clazz) { Object [] array = (Object[])java.lang.reflect.Array.newInstance(clazz, 1); array = gson.fromJson(json, array.getClass()); List<T> list = new ArrayList<T>(); for (int i=0 ; i<array.length ; i++) list.add((T)array[i]); return list; } 

我想补充一个可能性。 如果你不想使用TypeToken,并想要将json objects数组转换为ArrayList,那么你可以像这样继续:

如果你的json结构是这样的:

 { "results": [ { "a": 100, "b": "value1", "c": true }, { "a": 200, "b": "value2", "c": false }, { "a": 300, "b": "value3", "c": true } ] 

}

而你的class级结构就像

 public class ClassName implements Parcelable { public ArrayList<InnerClassName> results = new ArrayList<InnerClassName>(); public static class InnerClassName { int a; String b; boolean c; } } 

那么你可以像parsing它:

 Gson gson = new Gson(); final ClassName className = gson.fromJson(data, ClassName.class); int currentTotal = className.results.size(); 

现在你可以访问className对象的每个元素。

我喜欢kays1的答案,但我无法实现它。 所以我用他的概念build立了自己的版本。

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

在我的情况@ uncaught_exceptions的答案没有工作,我不得不使用List.class而不是java.lang.reflect.Type

 String jsonDuplicatedItems = request.getSession().getAttribute("jsonDuplicatedItems").toString(); List<Map.Entry<Product, Integer>> entries = gson.fromJson(jsonDuplicatedItems, List.class); 

有关Gson的“types”类理解,请参阅示例2。

例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()); } } 

对于Kotlin来说:

 import java.lang.reflect.Type import com.google.gson.reflect.TypeToken ... val type = object : TypeToken<ArrayList<T>>() {}.type 

或者,这里是一个有用的function:

 fun <T> buildType(): Type { return object : TypeToken<ArrayList<T>>() {}.type } 

然后,使用:

 val type = buildType<ArrayList<YourMagicObject>>()