如何使用Google GSON将JSON数组反序列化为generics类型的集合?

我正在编写一些代码,用于从网站中检索资源。 它看起来像这样:

public Collection getProjects() { String json = getJsonData(methods.get(Project.class)); //Gets a json list, ie [1, 2, 3, 4] Gson gson = new Gson(); Type collectionType = new TypeToken<Collection>() {}.getType(); return gson.fromJson(json, collectionType); } 

所以我很自然地尝试使用Javagenerics来抽象它。

 /* * Deserialize a json list and return a collection of the given type. * * Example usage: getData(AccountQuota.class) -> Collection */ @SuppressWarnings("unchecked") public  Collection getData(Class cls) { String json = getJsonData(methods.get(cls)); //Gets a json list, ie [1, 2, 3, 4] Gson gson = new Gson(); Type collectionType = new TypeToken<Collection>(){}.getType(); return (Collection) gson.fromJson(json, collectionType); } 

虽然代码的通用版本不太有用。

 public void testGetItemFromGetData() throws UserLoginError, ServerLoginError { Map userData = GobblerAuthenticator.authenticate("foo@example.com", "mypassword"); String client_key = userData.get("client_key"); GobblerClient gobblerClient = new GobblerClient(client_key); ArrayList machines = new ArrayList(); machines.addAll(gobblerClient.getData(Project.class)); assertTrue(machines.get(0).getClass() == Project.class); Log.i("Machine", gobblerClient.getData(Project.class).toString()); } java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.gobbler.synchronization.Machine at com.gobblertest.GobblerClientTest.testGetItemFromGetData(GobblerClientTest.java:53) at java.lang.reflect.Method.invokeNative(Native Method) at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169) at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154) at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:545) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1551) 

有问题的课程:

 import java.util.Map; public class Project { private int total_bytes_stored; private String name; private String user_data_guid; private int seqnum; private String guid; private Map current_checkpoint; private Map upload_folder; // TODO: schema_version private boolean deleted; // TODO: download_folders public Project() {} // No args constructor used for GSON } 

我不太熟悉Javagenerics或GSON内部的所有细节,我的搜索并不是特别有用。 这里有很多关于SO的问题,但是大多数问题都是像我原来那样实现的方法。 GSON文档似乎没有涉及这个特殊情况。 再说一遍,我如何使用Google GSON将JSON数组反序列化为generics类型的集合?

可悲的是,你做不到。 generics类型已被编译器删除,Gson无法知道您拥有的类型或字段是什么。

我想你可以! 来自Gson用户指南 :

您可以通过为generics类型指定正确的参数化类型来解决此问题。 您可以使用TypeToken类来完成此操作。

这意味着你可以在理论上将你的地图包裹起来:

 Type t = new TypeToken>() {}.getType(); Map map = (Map) new Gson().fromJson("json", t); 

或者(在我的情况下)我必须像这样包装一个List:

 Type t = new TypeToken>() {}.getType(); List list = (List) new Gson().fromJson("json", t); for (SearchResult r : list) { System.out.println(r); } 

(我得到了exception“java.lang.ClassCastException:com.google.gson.internal.StringMap无法强制转换为my.SearchResult” 。)

我使用JsonReader反序列化json字符串如下。

 public class JSONReader { ..... private Class persistentClass; public Class getPersistentClass() { if (persistentClass == null) { this.persistentClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } return persistentClass; } public List read(Reader reader) throws IOException { JsonReader jsonReader = new JsonReader(reader); List objs = new ArrayList(); jsonReader.beginArray(); while (jsonReader.hasNext()) { T obj = (new Gson()).fromJson(jsonReader, getPersistentClass()); if (logger.isFine()) { logger.fine(obj.toString()); } objs.add(obj); } jsonReader.endArray(); jsonReader.close(); return objs; } ..... } 

你可以调用上面的方法使用下面的语句(将Json字符串转换为StringReader,并将StringReader对象传递给方法):

 public class Test extends JSONReader { ..... public List parse(String jsonString) throws IOException { StringReader strReader = new StringReader(jsonString); List objs = read(strReader); return objs; } ..... } 

希望可以工作!

我在Java中可以想到的最通用的类​​型是Map来表示JSON对象,而List>来表示JSON对象的数组。

使用GSON库解析它是非常简单的(我在撰写本文时使用的是2.2.4版):

 import com.google.gson.Gson; import java.util.List; import java.util.Map; public class Test { public static void main(String[] args) { String json = "{\"name\":\"a name\"}"; Gson GSON = new Gson(); Map parsed = GSON.fromJson(json, Map.class); System.out.println(parsed.get("name")); String jsonList = "[{\"name\":\"a name\"}, {\"name\":\"a name2\"}]"; List> parsedList = GSON.fromJson(jsonList, List.class); for (Map parsedItem : parsedList) { System.out.println(parsedItem.get("name")); } } }