@AllArgsConstructor与@JsonFormat一起使用时遇到的问题及对序列化的理解

2023-03-13 08:18:58

问题描述:

有以下实体类:

@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"

正常,没有异常。

  • 作者:石头成说
  • 原文链接:https://blog.csdn.net/qq_27127145/article/details/98880237
    更新时间:2023-03-13 08:18:58