Jackson反序列化原理

Posted by SFHJavaer on 2025-05-29
Estimated Reading Time 3 Minutes
Words 859 In Total
Viewed Times

今天碰到一个问题,后端使用LocalDate mDate接收,看起来很正常,但是后台一直接收不到参数,猜想是DateFormat(pattern = ‘yyyy-MM-dd’),结果还是不生效

发现是Jackson反序列化失败了

这里不会提示报错信息,仅仅映射不上值为null而已

我们知道,boolean属性使用is开头会存在冲突,原因就是boolean的set方法(比如使用Lombook等生成),会自动加入is开头

那么第二个字母为大写,同样会产生此问题,原因就是Jasckson的反序列化是完全根据set方法反向寻找的

反序列化的时候获取属性,除去Boolen类型都是通过set***转换来的,转换的方法为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
protected static String legacyManglePropertyName(final String basename, final int offset)
{
final int end = basename.length();
if (end == offset) { // empty name, nope
return null;
}
// next check: is the first character upper case? If not, return as is
char c = basename.charAt(offset);
char d = Character.toLowerCase(c);

if (c == d) {
return basename.substring(offset);
}
// otherwise, lower case initial chars. Common case first, just one char
StringBuilder sb = new StringBuilder(end - offset);
sb.append(d);
int i = offset+1;
for (; i < end; ++i) {
c = basename.charAt(i);
d = Character.toLowerCase(c);
if (c == d) {
sb.append(basename, i, end);
break;
}
sb.append(d);
}
return sb.toString();
}

如果不手动写明set而使用生成的,比如name属性生成为setName()

Jackson遍历set之后的名称,因为常规属性约定都是小写开头,所以以Name为例:

1
2
3
4
5
6
7
8
for(遍历set剩余部分){
if(字母为大写){
转小写;
}
if(字母为小写){
直接拼接后面全部字符 这里 = 映射 'name'
}
}

所以对应mDate的setMDate方法

第一个字母自动转,后续转小写,所以得到的属性是 ’mdate‘,所以前端传mDate是接收不到的


这也是为什么后端写MDATE,前端传MDATE也能接受到,原因是setmDate,找到第一个m,直接就自动返回全量了

所以只要是大写开头的属性,直接就返回了,前端一定能映射上,但是不符合命名规范,一般不会出现。


那么aaDate呢?setAaDate,A转小写,第二个a直接返回 = aaDate也能映射

所以注意第二个字符大写问题,命名规范上不建议第一个单词为单字母,至少为标准单词:两个字母以上。




改造

由于进行了包拆分,抽象基类需要放到公共服务包中,且pojo移动到了dto包,所以只能基类包引dto包是合理的,反之则不合理,因为接受请求属于是运行时操作,此时引入反序列化改造。

核心方法为deserialize,去获取Jackson对象的值转Json再转对象,但是此时有个坑,前端控件在第一次刷新进入时传给后端的是null,填写再清空此时传的json为 “”


当传值为""时,JSON.parseObject可以正常转换为LocalDate的null,但是如果是空,这里会抛出异常:

:::info
“DateTimeParseException: Text ‘null’ could not be parsed at index 0”

:::

很明显不允许从null,转向LocalDate类型,认为是不合法的JSON,难道起码应当有个""????

Debug

发现JsonNode(ObjectNode) 的元素,Json(LocalDate/String)默认解析的都是TextNode(“null”)

然后在writeValueAsString会转成:

所以"null"字符串是肯定不能转LocalDate的,所以 Text ‘null’ 指的是String文本

所以修复

置空json串达到效果


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !