您的位置:首页 > 编程语言 > Java开发

Gson使用心得(二):Map反序列化的一个陷阱

2015-12-30 11:40 651 查看
今天来讲java.util.Map的序列化和反序列化。

当中有一个陷阱,匪夷所思,请看代码。

import java.util.Date;
import java.util.Hashtable;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

public class DateGsonTest {

private String name;

private Date birthday;

public static void main(String[] args) {
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

DateGsonTest dgt1 = new DateGsonTest();
dgt1.setName("Lance");
dgt1.setBirthday(new Date(537465600000l));

DateGsonTest dgt2 = new DateGsonTest();
dgt2.setName("Azure");
dgt2.setBirthday(new Date(573235200000l));

Map<String, DateGsonTest> dgtMap = new Hashtable<String, DateGsonTest>();
dgtMap.put(dgt1.getName(), dgt1);
dgtMap.put(dgt2.getName(), dgt2);
// dgtMap.put("Description", "This is a DateGsonTest map.");

String dgtMapStr = gson.toJson(dgtMap);
System.out.println(dgtMapStr);

Map<String, DateGsonTest> dgtMapTemp = gson.fromJson(dgtMapStr, new TypeToken<Hashtable<String, DateGsonTest>>() {
}.getType());

System.out.println("The json string of Lance:" + dgtMapTemp.get("Lance"));
System.out.println("The json string of Azure:" + dgtMapTemp.get("Azure"));
// System.out.println("The Description:" + dgtMapTemp.get("Description"));
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

}


第32行的输出为:

{
"Azure": {
"name": "Azure",
"birthday": "1988-03-02 00:00:00"
},
"Lance": {
"name": "Lance",
"birthday": "1987-01-13 00:00:00"
}
}


第37、38行的输出为:

The json string of Lance:DateGsonTest@51507e7
The json string of Azure:DateGsonTest@27b9d14c


程序没有任何异常,所以我想说明的并不是这个。

在某些情况下,Map中存放的数据类型并不是确定的,也不能用泛型来限定。

import java.util.Date;
import java.util.Hashtable;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

public class DateGsonTest {

private String name;

private Date birthday;

public static void main(String[] args) {
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

DateGsonTest dgt1 = new DateGsonTest();
dgt1.setName("Lance");
dgt1.setBirthday(new Date(537465600000l));

DateGsonTest dgt2 = new DateGsonTest();
dgt2.setName("Azure");
dgt2.setBirthday(new Date(573235200000l));

Map<String, Object> dgtMap = new Hashtable<String, Object>();
dgtMap.put(dgt1.getName(), dgt1);
dgtMap.put(dgt2.getName(), dgt2);
dgtMap.put("Description", "This is a DateGsonTest map.");

String dgtMapStr = gson.toJson(dgtMap);
System.out.println(dgtMapStr);

Map<String, Object> dgtMapTemp = gson.fromJson(dgtMapStr, new TypeToken<Hashtable<String, Object>>() {
}.getType());

System.out.println("The json string of Lance:" + dgtMapTemp.get("Lance"));
System.out.println("The json string of Azure:" + dgtMapTemp.get("Azure"));
System.out.println("The Description:" + dgtMapTemp.get("Description"));

DateGsonTest Lance = gson.fromJson(dgtMapTemp.get("Lance").toString(), DateGsonTest.class);
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

}


此时,Map<String, DateGsonTest> 必须修改成 Map<String, Object>

第32行的输出为:

{
"Azure": {
"name": "Azure",
"birthday": "1988-03-02 00:00:00"
},
"Description": "This is a DateGsonTest map.",
"Lance": {
"name": "Lance",
"birthday": "1987-01-13 00:00:00"
}
}


此时,这段Json字符串仍然是没有问题的。出问题的是第37、38行的输出:

The json string of Lance:{name=Lance, birthday=1987-01-13 00:00:00}
The json string of Azure:{name=Azure, birthday=1988-03-02 00:00:00}


经过gson一次反序列化后,DateGsonTest 对象Json字符串上的引号莫名其妙消失了。。。然后41行妥妥的抛了一个异常:

Exception in thread "main" com.google.gson.JsonSyntaxException: 1987-01-13
at com.google.gson.DefaultDateTypeAdapter.deserializeToDate(DefaultDateTypeAdapter.java:107)
at com.google.gson.DefaultDateTypeAdapter.deserialize(DefaultDateTypeAdapter.java:82)
at com.google.gson.DefaultDateTypeAdapter.deserialize(DefaultDateTypeAdapter.java:35)
at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:58)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:217)
at com.google.gson.Gson.fromJson(Gson.java:814)
at com.google.gson.Gson.fromJson(Gson.java:779)
at com.google.gson.Gson.fromJson(Gson.java:728)
at com.google.gson.Gson.fromJson(Gson.java:700)
at DateGsonTest.main(DateGsonTest.java:41)
Caused by: java.text.ParseException: Unparseable date: "1987-01-13"
at java.text.DateFormat.parse(DateFormat.java:357)
at com.google.gson.DefaultDateTypeAdapter.deserializeToDate(DefaultDateTypeAdapter.java:105)
... 10 more


这是我在实战中碰到的真实案例简化的,当时心中仿佛有一万头草泥马在奔腾。。。

好了,现在说说一个临时的解决方案。为了保障最终DateGsonTest 对象能被正确反序列化,在DateGsonTest 放入Map之前,对象必须先被序列化一次。如下所示:

import java.util.Date;
import java.util.Hashtable;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

public class DateGsonTest {

private String name;

private Date birthday;

public static void main(String[] args) {
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

DateGsonTest dgt1 = new DateGsonTest();
dgt1.setName("Lance");
dgt1.setBirthday(new Date(537465600000l));

DateGsonTest dgt2 = new DateGsonTest();
dgt2.setName("Azure");
dgt2.setBirthday(new Date(573235200000l));

Map<String, Object> dgtMap = new Hashtable<String, Object>();
dgtMap.put(dgt1.getName(), gson.toJson(dgt1));
dgtMap.put(dgt2.getName(), gson.toJson(dgt2));
dgtMap.put("Description", "This is a DateGsonTest map.");

String dgtMapStr = gson.toJson(dgtMap);
System.out.println(dgtMapStr);

Map<String, Object> dgtMapTemp = gson.fromJson(dgtMapStr, new TypeToken<Hashtable<String, Object>>() {
}.getType());

System.out.println("The json string of Lance:" + dgtMapTemp.get("Lance"));
System.out.println("The json string of Azure:" + dgtMapTemp.get("Azure"));
System.out.println("The Description:" + dgtMapTemp.get("Description"));

DateGsonTest Lance = gson.fromJson(dgtMapTemp.get("Lance").toString(), DateGsonTest.class);
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

}


此时32行的输出为:

{
"Azure": "{\"name\":\"Azure\",\"birthday\":\"1988-03-02 00:00:00\"}",
"Description": "This is a DateGsonTest map.",
"Lance": "{\"name\":\"Lance\",\"birthday\":\"1987-01-13 00:00:00\"}"
}


然后37、38行的输出为:

The json string of Lance:{"name":"Lance","birthday":"1987-01-13 00:00:00"}
The json string of Azure:{"name":"Azure","birthday":"1988-03-02 00:00:00"}


世界终于清净了。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  gson java Json