如何把如下简单的JSON字符串反序列化为Java的POJO对象?
{"data":{"IM":["MSN","QQ","Gtalk"]}}
下面的POJO类Model无法完成正确的解析:
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Model {
private Map<String, Map<String, List<String>>> data;
public Map<String, Map<String, List<String>>> getData() {
return data;
}
public void setData(Map<String, Map<String, List<String>>> data) {
this.data = data;
}
}
public class ModelTest {
public static void main(String[] args) {
List<String> ims = new ArrayList<String>();
ims.add("MSN");
ims.add("QQ");
ims.add("Gtalk");
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("IM", ims);
Map<String, Map<String, List<String>>> dataMap = new HashMap<String, Map<String, List<String>>>();
dataMap.put("data", map);
String str = new Gson().toJson(dataMap);
System.out.println(str);/*{"data":{"IM":["MSN","QQ","Gtalk"]}}*/
Model m = new Gson().fromJson(str, Model.class);
}
}
异常信息:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 17
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
at com.google.gson.Gson.fromJson(Gson.java:803)
at com.google.gson.Gson.fromJson(Gson.java:768)
at com.google.gson.Gson.fromJson(Gson.java:717)
at com.google.gson.Gson.fromJson(Gson.java:689)
at gson.test4.ModelTest.main(ModelTest.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 17
at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:338)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:172)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:187)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172)
... 10 more
如何解决这个问题?
仔细看了代码,出错是正常的事情。在代码中,str是从dataMap序列化而来,把这个由dataMap转换而来的JSON串str反序列为Model类型,出错是必然的
String str = new Gson().toJson(dataMap);
Model m = new Gson().fromJson(str, Model.class)
那么Model对象序列化为JSON串的数据是什么样的呢?
{"data":{"data":{"IM":["MSN","QQ","Gtalk"]}}}
此时,解决的办法有两个:
1. 对于下面的JSON串,对应的数据结构是Map<String,Map<String,List<String>>>,直接把这个这个JSON串转成Map<String,Map<String,List<String>>>是可行的,比如如下的代码
{"data":{"IM":["MSN","QQ","Gtalk"]}}
将它转换为Map<String,Map<String,List<String>>>
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Model {
private Map<String, Map<String, List<String>>> data;
public Map<String, Map<String, List<String>>> getData() {
return data;
}
public void setData(Map<String, Map<String, List<String>>> data) {
this.data = data;
}
}
public class ModelTest {
public static void main(String[] args) {
List<String> ims = new ArrayList<String>();
ims.add("MSN");
ims.add("QQ");
ims.add("Gtalk");
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("IM", ims);
Map<String, Map<String, List<String>>> dataMap = new HashMap<String, Map<String, List<String>>>();
dataMap.put("data", map);
String str = new Gson().toJson(dataMap);
System.out.println(str);/*{"data":{"IM":["MSN","QQ","Gtalk"]}}*/
Type type = new TypeToken<Map<String, Map<String, List<String>>>>(){}.getType();
dataMap = new Gson().fromJson(str, type);
ims= dataMap.get("data").get("IM");
for(int i = 0; i< ims.size(); i++) {
System.out.println(ims.get(i));
}
}
}
2.重新定义Model的数据结构,它包含的数据类型应该是private Map<String, List<String>> data;代码如下,此时可以正确解析了
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Model {
private Map<String, List<String>> data;
public Map<String, List<String>> getData() {
return data;
}
public void setData(Map<String, List<String>> data) {
this.data = data;
}
}
public class ModelTest {
public static void main(String[] args) {
List<String> ims = new ArrayList<String>();
ims.add("MSN");
ims.add("QQ");
ims.add("Gtalk");
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("IM", ims);
Map<String, Map<String, List<String>>> dataMap = new HashMap<String, Map<String, List<String>>>();
dataMap.put("data", map);
String str = new Gson().toJson(dataMap);
System.out.println(str);/*{"data":{"IM":["MSN","QQ","Gtalk"]}}*/
Model m = new Gson().fromJson(str, Model.class);
System.out.println(m!=null);
}
}
3.第三种方式,不使用Type,直接使用Map.class,这时没有使用范型,但是仍然可以得到正确的输出,这是为什么??
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Model {
private Map<String, Map<String, List<String>>> data;
public Map<String, Map<String, List<String>>> getData() {
return data;
}
public void setData(Map<String, Map<String, List<String>>> data) {
this.data = data;
}
}
public class ModelTest {
public static void main(String[] args) {
List<String> ims = new ArrayList<String>();
ims.add("MSN");
ims.add("QQ");
ims.add("Gtalk");
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("IM", ims);
Map<String, Map<String, List<String>>> dataMap = new HashMap<String, Map<String, List<String>>>();
dataMap.put("data", map);
String str = new Gson().toJson(dataMap);
System.out.println(str);/*{"data":{"IM":["MSN","QQ","Gtalk"]}}*/
//Type type = new TypeToken<Map<String, Map<String, List<String>>>>(){}.getType();
//Map<String, Map<String, List<String>>> t = null;
dataMap = new Gson().fromJson(str, Map.class); //不使用Type包装范型,为什么仍然正确?
ims= dataMap.get("data").get("IM");
for(int i = 0; i< ims.size(); i++) {
System.out.println(ims.get(i));
}
}
}