Jackson2 反序列化: setter 方法重载的坑
- 这几天遇到一个自己埋的坑 :<( , 一个 bean 中有一个
LocalDateTime
字段, 用了注解或配置相应反序列化器, 都无法序列化, 就是提示错误:
com.fasterxml.jackson.databind.JsonMappingException: Problem deserializing property 'expireTime' (expected type: [simple type, class int]; actual type:
`java.time.LocalDateTime`), problem: argument type mismatch
at [Source: (String)"{"code":"5ddj","expireTime":"2020-10-31 10:59:44 811","reuse":false,"image":null,"expired":false}"; line: 1, column: 29] (through reference chain:
top.dcenter.ums.security.core.auth.validate.codes.image.ImageCode["expireTime"])
一 相关配置:
Bean
@Getter
@Setter
@ToString
public class ValidateCode implements Serializable {
private static final long serialVersionUID = 8564646192066649173L;
private String code;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss SSS", locale = "zh", timezone = "GMT+8")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime expireTime;
/**
* 是否复用, 如果复用, 不会重新产生验证码, 仍使用验证码失败的验证码
*/
private Boolean reuse;
public ValidateCode() {
this.code = null;
this.expireTime = null;
this.reuse = false;
}
/**
* 验证码构造器: 默认 <pre>reuse = false;</pre> 不复用
* @param code 验证码
* @param expireIn 秒
*/
public ValidateCode(String code, int expireIn) {
this.code = code;
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
reuse = false;
}
public void setExpireTime(int expireIn) {
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
}
/**
* 验证码构造器: 默认不复用
* @param code 验证码
* @param expireIn 过期日期
* @param reuse 是否复用, 如果复用, 不会重新产生验证码, 仍使用验证码失败的验证码, 默认: false 即不复用
*/
public ValidateCode(String code, int expireIn, Boolean reuse) {
this.code = code;
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
this.reuse = reuse;
}
public boolean isExpired() {
return LocalDateTime.now().isAfter(expireTime);
}
}
- 该配置的都配置了, 就是反序列化错误, 总不能有
LocalDateTime
的bean
都自定义一个反序列化器吧!
二 最后没办法只能 DEBUG ObjectMapper
流程:
1.
LocalDateTime
反序列化是成功的2. 在调用
set
方法时失败了
最终原因在这里: 该方法入参为int
,因为这个方法当时为了方便设置过期时间添加的, 与规范的setter
方法是重载关系, 我用的是lombok @setter
方式, 因于字段expireTime
的set
方法重名,lombok
就不生成setter
方法了. 感觉找到原因了, 手动添加expireTime
的set
方法, 应该可以解决问题了, 结果还是我太年轻了:)- 3. 手动添加
expireTime
set
方法,还是反序列化失败
@Getter
@Setter
@ToString
public class ValidateCode implements Serializable {
// ... 略
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss SSS", locale = "zh", timezone = "GMT+8")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime expireTime;
public void setExpireTime(LocalDateTime expireTime) {
this.expireTime = expireTime;
}
public void setExpireTime(int expireIn) {
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
}
/... 略
}
三 分析因 setExpireTime(obj)
方法重载反序列化失败的原因:
四 解决方案
: 因为知道了具体的问题所在, 就更容易解决了
第一种方案(推荐):
Jackson
注释放到setExpireTime(..)
方法上.@Getter @Setter @ToString public class ValidateCode implements Serializable { // ... 略 private LocalDateTime expireTime; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss SSS", locale = "zh", timezone = "GMT+8") @JsonDeserialize(using = LocalDateTimeDeserializer.class) public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } public void setExpireTime(int expireIn) { this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } /... 略 }
第二种方案:
重命名
重载的方法.@Getter @Setter @ToString public class ValidateCode implements Serializable { // ... 略 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss SSS", locale = "zh", timezone = "GMT+8") @JsonDeserialize(using = LocalDateTimeDeserializer.class) private LocalDateTime expireTime; public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } public void setExpireIn(int expireIn) { this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } /... 略 }
五 想法: 能否提个 PR 给 Jackson
解决这个方法重载的问题
哎, 想的挺美, 想法于现实总是相左.
正文到此结束