我正在编写一些将用于从网站检索资源的代码。它看起来像这样:
public Collection<Project> 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<Project>>() {}.getType();
return gson.fromJson(json, collectionType);
}
很自然地,我尝试使用Java泛型来抽象它。
/*
* Deserialize a json list and return a collection of the given type.
*
* Example usage: getData(AccountQuota.class) -> Collection<AccountQuota>
*/
@SuppressWarnings("unchecked")
public <T> Collection<T> getData(Class<T> 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<T>>(){}.getType();
return (Collection<T>) gson.fromJson(json, collectionType);
}
虽然代码的通用版本不太适用。
public void testGetItemFromGetData() throws UserLoginError, ServerLoginError {
Map<String,String> userData = GobblerAuthenticator.authenticate("foo@example.com", "mypassword");
String client_key = userData.get("client_key");
GobblerClient gobblerClient = new GobblerClient(client_key);
ArrayList<Project> machines = new ArrayList<Project>();
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<String, String> upload_folder;
// TODO: schema_version
private boolean deleted;
// TODO: download_folders
public Project() {} // No args constructor used for GSON
}
我不太熟悉Java泛型或GSON内部的所有细节,但我的搜索并不是特别有用。这里有很多关于SO的问题,但是大多数都提到了像我原来那样的实现方法。并GSON docs似乎没有涉及这个特殊情况。那么,我怎样才能使用Google GSON将JSON数组反序列化为泛型类型的集合?
答案 0 :(得分:33)
我想你可以! From the Gson user guide:
您可以通过为通用类型指定正确的参数化类型来解决此问题。您可以使用TypeToken类来完成此操作。
这意味着您理论上可以像这样包装地图:
Type t = new TypeToken<Map<String,Machine>>() {}.getType();
Map<String,Machine> map = (Map<String,Machine>) new Gson().fromJson("json", t);
或者(在我的情况下)我必须像这样包装一个List:
Type t = new TypeToken<List<SearchResult>>() {}.getType();
List<SearchResult> list = (List<SearchResult>) new Gson().fromJson("json", t);
for (SearchResult r : list) {
System.out.println(r);
}
(我收到异常“java.lang.ClassCastException:com.google.gson.internal.StringMap无法强制转换为my.SearchResult”。)
答案 1 :(得分:8)
答案 2 :(得分:5)
我使用JsonReader反序列化json字符串如下。
public class JSONReader<T> {
.....
private Class<T> persistentClass;
public Class<T> getPersistentClass() {
if (persistentClass == null) {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
return persistentClass;
}
public List<T> read(Reader reader) throws IOException {
JsonReader jsonReader = new JsonReader(reader);
List<T> objs = new ArrayList<T>();
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<MyClass> {
.....
public List<MyClass> parse(String jsonString) throws IOException {
StringReader strReader = new StringReader(jsonString);
List<MyClass> objs = read(strReader);
return objs;
}
.....
}
希望能有效!
答案 3 :(得分:1)
我在Java中可以想到的最通用的类型是表示JSON对象的Map<String, Object>
和表示JSON对象数组的List<Map<String, Object>>
。
使用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<String, Object> parsed = GSON.fromJson(json, Map.class);
System.out.println(parsed.get("name"));
String jsonList = "[{\"name\":\"a name\"}, {\"name\":\"a name2\"}]";
List<Map<String, Object>> parsedList = GSON.fromJson(jsonList, List.class);
for (Map<String, Object> parsedItem : parsedList) {
System.out.println(parsedItem.get("name"));
}
}
}