@AllArgsConstructor與@JsonFormat一起使用時遇到的問題及對序列化的理解

問題描述:

有以下實體類:

@Data
@ToString
@AllArgsConstructor
public class UpdateTargetInfoBean {

    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
    private Date endDate;

    /**
     * 存到數據庫裏的格式是yyyy-MM-dd
     */
    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
    private Date startDate;
}

這個實體類作爲前端的參數使用,前端傳遞該類的json數據,後端將其反序列爲Bean。請求接口如下:

    /**
     * 修改成員目標信息
     */
    @RequestMapping(value = "update/target", method = RequestMethod.POST, consumes = "application/json",produces = "application/json")
    @ResponseBody
    @ApiOperation("修改成員目標信息")
    public Response updateTarget(@RequestBody UpdateTargetInfoBean updateTargetInfo) throws DataFormatErrorException, DataNotExistException {
        memberTargetService.updateTarget(updateTargetInfo);
        return Response.ok();
    }

當前端傳遞:

"endDate":"2019-08-18 00:00:00","startDate":"2019-08-08 14:35:12"

會報InvalidDefinitionException異常:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.laisi.balance.model.target.UpdateTargetInfoBean` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (PushbackInputStream); line: 1, column: 2]

當去掉@AllArgsConstructor註解時,異常消失。

解惑:

先看我摘抄的一段話:

要想將父類對象也序列化,就需要讓父類也實現Serializable 接口。如果父類不實現的話的,就需要有默認的無參的構造函數。 在父類沒有實現 Serializable 接口時,虛擬機是不會序列化父對象的,而一個 Java 對象的構造必須先有父對象,纔有子對象,反序列化也不例外。所以反序列化時,爲了構造父對象,只能調用父類的無參構造函數作爲默認的父對象。因此當我們取 父對象的變量值時,它的值是調用父類無參構造函數後的值。如果你考慮到這種序列化的情況,在父類無參構造函數中對變量進行初始化,否則的話,父類變量值都 是默認聲明的值,如 int 型的默認是 0,string 型的默認是 null。

這段話是說對象的序列化與反序列化,自己和父類必須實現Serializable 接口,或者自己有默認的無參的構造函數。

我驗證了一下,當自己與父類均實現Serializable 接口的情況下,反序列化報異常如下:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.laisi.balance.model.target.UpdateTargetInfoBean` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (PushbackInputStream); line: 1, column: 2]

說明上面結論“對象的序列化與反序列化,自己和父類必須實現Serializable 接口”錯誤。

當類有無參構造函數時,正常;沒有無參構造函數時,也報上面的異常。

說明結論:“對象的序列化與反序列化,自己必須有默認的無參的構造函數”正確。

注意:JVM會在類中沒有任何構造函數的情況下,默認會在編譯class文件時,給Java類一個無參的構造函數,如果類有了有參的構造函數,就不會再默認給一個無參的了。這時,需要自己寫一個無參的構造函數,或者使用lombok的@NoArgsConstructor註解。因爲我的實體類UpdateTargetInfoBean使用了@AllArgsConstructor註解,有了有參的構造函數,JVM就不會提供無參構造函數了,導致出現異常。我之前有個誤區,認爲lombok的@Data註解,該註解會提供無參構造函數方法,經驗證是錯誤的,它只會提供get/set/equal/hashCoded等方法。

再說 @JsonFormat

@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")經驗證,這個註解是規定了Date反序列化需要的json數據格式。只要json前綴是"yyyy-MM-dd "格式的就可以,例如"2019-08-18","2019-08-08 14:35:12"或者"2019-08-08 asasq",都會序列化爲Date類型(Thu Aug 08 00:00:00 CST 2019)。這個註解只對set方法起作用。

 

傳遞:

"endDate":"2019-08-18","startDate":"2019-08-08"

正常,沒有異常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章