美文网首页
DateTime系列化与返系列化,Json解析问题

DateTime系列化与返系列化,Json解析问题

作者: Darshan | 来源:发表于2019-05-24 17:26 被阅读0次

前言

目前,公司的项目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性能分析

相关文章

网友评论

      本文标题:DateTime系列化与返系列化,Json解析问题

      本文链接:https://www.haomeiwen.com/subject/oqajzqtx.html