前言
目前,公司的项目app端与后台端通信时间采用的是DateTime类时间对象。这是一个第三方的时间类,转为字符串的时间格式为"2019-05-21T00:00:00+0800"。但是采用Gson转换时格式就不识别了,变成了这样:
datetime to jsonStr = {"iChronology":{"iBase":{"iBase":{"iBase":{"iMinDaysInFirstWeek":4}},"iParam":
{"iZone":{"iNameKeys":
["LMT","CST","CDT","CST","CDT","CST","CDT","CST","CDT","CST","CDT","CST","CDT","CST","CDT","CST","CDT","CST"
],"iStandardOffsets":
[29143000,28800000,28800000,28800000,28800000,28800000,28800000,28800000,28800000,28800000,28800000,28800000
,28800000,28800000,28800000,28800000,28800000,28800000],"iTransitions":[-9223372036854775808,-
2177481943000,-933494400000,-923130000000,-908784000000,-
891594000000,515520000000,527007600000,545155200000,558457200000,576604800000,589906800000,608659200000,6219
61200000,640108800000,653410800000,671558400000,684860400000],"iWallOffsets":
[29143000,28800000,32400000,28800000,32400000,28800000,32400000,28800000,32400000,28800000,32400000,28800000
,32400000,28800000,32400000,28800000,32400000,28800000],"iID":"Asia/Shanghai"},"iID":"Asia/Shanghai"}}},"iMi
llis":1558433492780}
变成这样的格式既不是我们想要的,也变不回我们想要的DateTime。在做网络上传和数据保存在SharedPreferences中就遇到了很大的问题。
Gson解析的原理
Gson这个框架主要是为了解决java对象与json之间相互转换的。Gson提供了JsonDeserializer, JsonSerializer接口和TypeAdapter适配类来给对象做系列化和返系列化,如果不实现这些方法就会采用默认的方法。
DateTime解析的解决办法
既然Gson解析不识别DateTime,那我们可以实现Gson提供给我们的系列化和返系列化的方法自己做处理。这就有两种实现方法
办法一
Gson gson = new GsonBuilder().registerTypeAdapter(NoticeVo.class, new NoticeVoDataTimeAdapter()).create();
首先设置Gson注册我们自己继承TypeAdapter实现的转换类,主要重写write(JsonWriter out, NoticeVo value)和read(JsonReader in) 方法。此实现类采用流的方式来实现系列化和返系列化。把我们需要转换的对象的属性一一转换,其中我们的关键属性DateTime就得做好转换的格式了。
//系列化
out.name("releaseDatetime").value(value.getReleaseDatetime().toString("yyyy-MM-dd'T'HH:mm:ssZ"));
//返系列化
vo.setReleaseDatetime(DateTime.parse(in.nextString()));
NoticeVo对象的系列化和返系列化的适配类
public class NoticeVoDataTimeAdapter extends TypeAdapter<NoticeVo> {
@Override
public void write(JsonWriter out, NoticeVo value) throws IOException {
out.beginObject(); //流式序列化成对象开始
out.name("description").value(value.getDescription());
out.name("detailFileUrl").value(value.getDetailFileUrl());
out.name("id").value(value.getId());
out.name("introduction").value(value.getIntroduction());
out.name("isRead").value(value.getIsRead());
out.name("noticeTargetId").value(value.getNoticeTargetId());
out.name("picPath").value(value.getPicPath());
out.name("title").value(value.getTitle());
out.name("releaseDatetime").value(value.getReleaseDatetime().toString("yyyy-MM-dd'T'HH:mm:ssZ"));
out.endObject();
}
@Override
public NoticeVo read(JsonReader in) throws IOException {
in.beginObject();
NoticeVo vo = new NoticeVo();
while (in.hasNext()) {
switch (in.nextName()) {
case "description":
vo.setDescription(in.nextString());
break;
case "detailFileUrl":
vo.setDetailFileUrl(in.nextString());
break;
case "id":
vo.setId(in.nextString());
break;
case "introduction":
vo.setIntroduction(in.nextString());
break;
case "isRead":
vo.setIsRead(in.nextBoolean());
break;
case "noticeTargetId":
vo.setNoticeTargetId(in.nextString());
break;
case "picPath":
vo.setPicPath(in.nextString());
break;
case "title":
vo.setTitle(in.nextString());
break;
case "releaseDatetime":
vo.setReleaseDatetime(DateTime.parse(in.nextString()));
break;
}
}
in.endObject();
return vo;
}
}
办法二
首先设置Gson注册我们自己实现 JsonDeserializer<DateTime>, JsonSerializer<DateTime>接口的转换类,在转换类里实现deserialize和serialize方法。
new GsonBuilder()
.setPrettyPrinting()
.serializeNulls()
.registerTypeAdapter(DateTime.class, new DateTimeSerializer())
.create();
/**
* DateTime系列化与返系列化格式转换
*/
public class DateTimeSerializer implements JsonDeserializer<DateTime>, JsonSerializer<DateTime> {
private static DateTimeFormatter TIME_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ");
@Override
public DateTime deserialize(final JsonElement je, final Type type,
final JsonDeserializationContext jdc) throws JsonParseException {
final String dateAsString = je.getAsString();
if (dateAsString.length() == 0) {
return null;
} else {
return DateTime.parse(dateAsString, TIME_FORMAT);
}
}
@Override
public JsonElement serialize(final DateTime src, final Type typeOfSrc,
final JsonSerializationContext context) {
String retVal;
if (src == null) {
retVal = "";
} else {
retVal = TIME_FORMAT.print(src);
}
return new JsonPrimitive(retVal);
}
}
总结
这两种方法都能实现对象的系列化和返系列化。方法一是采用流转换的,效率会高一些,但方法一是针对某一对象的,需要把这个对象的所以属性都要写一遍,如果这个对象有很多属性那就会多做很多体力劳动,而且只能是当前对象能用,不同对象还要重写一遍。而方法二就不同了,可以针对某一对象的某一个属性,具有通用性。
参考文章
Gson全解析(上)-Gson基础
Gson全解析(中)-TypeAdapter的使用
Gson全解析(下)-Gson性能分析
网友评论