問題描述:
有以下實體類:
@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"
正常,沒有異常。