谷歌Gson – 反序列化列表<class>对象? (通用型)
我想通过谷歌Gson传递一个列表对象,但我不知道如何反序列化泛型类型。
我看了这个 (BalusC的回答)之后试了一下:
MyClass mc = new Gson().fromJson(result, new List<MyClass>(){}.getClass());
但是后来我在eclipse中得到一个错误:“新的List(){}类型必须实现继承的抽象方法…”,如果我使用快速修复,我会得到一个超过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,得到了以下结果:
- 列表类型
- args = ListOfTypes
- list = null
- resolvedTypes =类型[1]
- loader = PathClassLoader
- ownerType0 = null
- ownerTypeRes = null
- rawType = Class(java.util.ArrayList)
- rawTypeName =“java.util.ArrayList”
- args = ListOfTypes
所以看起来“getClass”调用没有正常工作。 有什么建议么…?
编辑2:我检查了Gson用户指南 。 它提到了在将一个泛型类型解析为Json的过程中发生的运行时异常。 我做了“错误”(上面没有显示),就像在这个例子中一样,但没有得到那个例外。 所以我改变了序列化在用户指南建议。 虽然没有帮助。
编辑3:解决,看到我的答案在下面。
反序列化泛型集合的方法:
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);
另一种方法是使用数组作为类型,例如:
MyClass[] mcArray = gson.fromJson(jsonString, MyClass[].class);
这样,您可以避免使用Type对象带来的麻烦,如果您确实需要列表,则始终可以通过以下方式将数组转换为列表:
List<MyClass> mcList = Arrays.asList(mcArray);
恕我直言,这是更可读。
为了使它成为一个真正的列表(可以修改,请参阅Arrays.asList()
限制),然后执行以下操作:
List<MyClass> mcList = new ArrayList<>(Arrays.asList(mcArray));
对于那些不明确的类型输入建议,这是你想要的。
import java.lang.reflect.Type;
参考这篇文章。 Java类型作为GSON的参数
我有更好的解决方案。 这里是列表的包装类,所以包装器可以存储确切类型的列表。
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);
创建一个扩展对象列表的空类:
public class YourClassList extends ArrayList<YourClass> {}
解析JSON时使用它:
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_180建议的List序列化和反序列化。
这是一个解决方案,与动态定义的类型一起工作。 诀窍是使用Array.newInstance()创建适当类型的数组。
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 } ]
}
而你的班级结构就像
public class ClassName implements Parcelable { public ArrayList<InnerClassName> results = new ArrayList<InnerClassName>(); public static class InnerClassName { int a; String b; boolean c; } }
那么你可以像解析它:
Gson gson = new Gson(); final ClassName className = gson.fromJson(data, ClassName.class); int currentTotal = className.results.size();
现在你可以访问className对象的每个元素。
我喜欢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);
在我的情况@ 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的“类型”类理解,请参阅示例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
或者,这里是一个有用的功能:
fun <T> buildType(): Type { return object : TypeToken<ArrayList<T>>() {}.type }
然后,使用:
val type = buildType<ArrayList<YourMagicObject>>()