ZonedDatatime的Jackson序列化问题


最近测试接口需要用到Jackson序列化和反序列化,其中发现对于时间类型的变量Jackson的序列化过程和反序列化过程不可逆,即序列化产生的结果无法被反序列化解析回ZonedDatatime对象,经过一番调整后问题解决,现将过程记录如下。
使用Jackson模块对ZonedDatetime序列化后产生结果的形式如下

{
    "offset": {
        "totalSeconds": 25200,
        "rules": {
            "fixedOffset": true,
            "transitionRules": [
            ],
            "transitions": [
            ],
            "class": "java.time.zone.ZoneRules"
        },
        "id": "+07:00",
        "class": "java.time.ZoneOffset"
    },
    "year": 2020,
    "dayOfYear": 181,
    "nano": 364000000,
    "chronology": {
        "calendarType": "iso8601",
        "id": "ISO",
        "class": "java.time.chrono.IsoChronology"
    },
    "minute": 15,
    "second": 38,
    "dayOfWeek": "MONDAY",
    "month": "JUNE",
    "hour": 18,
    "dayOfMonth": 29,
    "zone": {
        "rules": {
            "fixedOffset": true,
            "transitionRules": [
            ],
            "transitions": [
            ],
            "class": "java.time.zone.ZoneRules"
        },
        "id": "GMT+07:00",
        "class": "java.time.ZoneRegion"
    },
    "monthValue": 6,
    "class": "java.time.ZonedDateTime"
}

但是这个结果用Jackson进行反序列化后,类型为LocakDateTime的dataTime字段会被变成null。可以看到文本中也确实没有dateTime字段。

尝试手动进行LocalDateTime字段的转换

直接对一个LocalDatetime进行Jackson序列化

    public static void main(String[] args) throws JsonProcessingException {
        LocalDateTime time= LocalDateTime.now();
        String json=(new ObjectMapper()).writeValueAsString(time);
        System.out.println(json);
    }

显示的结果如下

{
    "dayOfMonth":7,
    "dayOfWeek":"TUESDAY",
    "dayOfYear":189,
    "hour":16,
    "minute":44,
    "month":"JULY",
    "monthValue":7,
    "nano":743000000,
    "second":54,
    "year":2020,
    "chronology":{
        "id":"ISO",
        "calendarType":"iso8601"
    }
}

对比上方的ZonedDateTime的序列化结果可以发现dateTime内的字段又被提了出来,所以将这些字段疯传到"dateTime"中似乎可以解决问题。但是之后又显示没有date对象。

LocalDate的序列化

阅读JDK源代码中的LocalDateTime发现

    /**
     * The date part.
     */
    private final LocalDate date;
    /**
     * The time part.
     */
    private final LocalTime time;

推测是LocalDateTime中同样出现了字段被拉平的问题,于是对LocalDate对象进行序列化,结果如下

    public static void main(String[] args) throws JsonProcessingException {
        LocalDate time=LocalDate.now();
        String json=(new ObjectMapper()).writeValueAsString(time);
        System.out.println(json);
    }

果不其然,结果如下

{
    "year":2020,
    "month":"JULY",
    "chronology":{
        "id":"ISO",
        "calendarType":"iso8601"
    },
    "dayOfMonth":7,
    "dayOfWeek":"TUESDAY",
    "dayOfYear":189,
    "era":"CE",
    "monthValue":7,
    "leapYear":true
}

LocalDate同样有自己的字段,也被提到了LocalDateTime中。虽然多了一些东西,但是只把LocalDateTime中也出现的进行整理就行,对LocalTime做同样的工作。

枚举值转化

经过这些操作后形式如下

{
    "offset": {
        "totalSeconds": 25200,
        "rules": {
            "fixedOffset": true,
            "transitionRules": [
            ],
            "transitions": [
            ],
            "class": "java.time.zone.ZoneRules"
        },
        "id": "+07:00",
        "class": "java.time.ZoneOffset"
    },
    "dateTime": {
        "date": {
            "year": 2019,
            "dayOfYear": 156,
            "chronology": {
                "calendarType": "iso8601",
                "id": "ISO",
                "class": "java.time.chrono.IsoChronology"
            },
            "dayOfWeek": "WEDNESSDAY",
            "month": "MAY",
            "dayOfMonth": 5,
            "monthValue": 6
        },
        "time": {
            "hour": 0,
            "minute": 0,
            "second": 0,
            "nano": 841000000
        },
        "class": "java.time.LocalDateTime"
    },
    "zone": {
        "rules": {
            "fixedOffset": true,
            "transitionRules": [
            ],
            "transitions": [
            ],
            "class": "java.time.zone.ZoneRules"
        },
        "id": "GMT+07:00",
        "class": "java.time.ZoneRegion"
    },
    "class": "java.time.ZonedDateTime"
}

本以为问题结束了,结果又出现了新问题,月份的MAY无法被识别。原因显而易见,上面的源代码中可以看到月份本来应该是数值类型的枚举的,结果在json中变成了字符串,因此将"MAY"改为5即可,其他月份同理。

最终结果

{
    "offset": {
        "totalSeconds": 25200,
        "rules": {
            "fixedOffset": true,
            "transitionRules": [
            ],
            "transitions": [
            ],
            "class": "java.time.zone.ZoneRules"
        },
        "id": "+07:00",
        "class": "java.time.ZoneOffset"
    },
    "dateTime": {
        "date": {
            "year": 2019,
            "dayOfYear": 156,
            "chronology": {
                "calendarType": "iso8601",
                "id": "ISO",
                "class": "java.time.chrono.IsoChronology"
            },
            "dayOfWeek": "WEDNESSDAY",
            "month": 6,
            "dayOfMonth": 5,
            "monthValue": 6
        },
        "time": {
            "hour": 0,
            "minute": 0,
            "second": 0,
            "nano": 841000000
        },
        "class": "java.time.LocalDateTime"
    },
    "zone": {
        "rules": {
            "fixedOffset": true,
            "transitionRules": [
            ],
            "transitions": [
            ],
            "class": "java.time.zone.ZoneRules"
        },
        "id": "GMT+07:00",
        "class": "java.time.ZoneRegion"
    },
    "class": "java.time.ZonedDateTime"
}

至此ZonedDateTime的json终于可以被Jackson识别并加载对象了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值