jackson1 处理特殊字符有什么问题?
说明
处理 json 是我们日常开发经常需要面对的问题,在经历过多种 json 工具的使用校验下,目前我们主要选择使用 jackson 作为处理 json 的工具。
目前 jackson 主要的两个大版本为 jackson1 和 jackson2,jackson1 已经将近是 10 年前的产物了,最新的一次更新也已经是 5 年前,可谓是古董级别的项目。
下面主要来聊聊使用 jackson1 特殊字符所遇到的问题。
jackson1 支不支持特殊字符?
这里的特殊字符怎么定义?
是指使用 4 个字节表示的表情,比如 emoji 表情
写个 demo 测试
1、首先定义一个 bean,里面包含 name 和 ext 属性:
2、使用 demo
3、测试结果
从测试结果来看 jackson1 将 json 字符串转成 bean 的时候,如果 json 字符串中的 key 在 bean 中都存在的情况下,jackson1 是可以正常处理特殊字符的。
所以大家正常情况使用 jackson1 是可以正常解析含有特殊字符串的 json。
jackson1 何时不支持特殊字符?
jackson1 也不是所有情况都支持特殊字符,比如在待解析 json 字符串中增加一个 address,而 bean 中不存在此属性:
测试结果:
从测试结果中我们发现结果异常了。。。所以我们从测试结果中可以得出以下结论:
jackson1 能够处理 bean 中存在的属性值具有特殊字符的情况
jackson1 不能够处理 bean 中不存在的属性值具有特殊字符的情况
于是我们需要考虑为什么,bean 中不存在的属性值中有特殊字符就会发生异常呢?
为什么会异常?
下面我们通过追踪 jackson 处理的方式来看看为什么会异常。
首先我们先简化需要测试 json 字符串(h 的具体值是:?):
以下将会通过 jackson 将上述 testJson 反序列化成 TestBean,经过分析我们将 testJson 的 byte 数组格式描述如下:
其中蓝色部分,7-10 为特殊字符?部分。
jackson1 在处理“h”的的时候会进入以下部分:
jackson1 在读取到 propName="h" 发现不再 bean 中的 prop 会继续执行到 jp.nextToken 中执行_skipString():
进入_skipString()方法以后会执行到以下部分:
这里主要逻辑是:jackson1 在读取到 bean 中不存在的属性,则会进入跳过这个 key 的 value 的逻辑,测试中需要从第 7 个位置跳到 10 个位置,如以下:
在执行 jackson1 中_skipUtf8_4()前:
在执行 jackson1 中_skipUtf8_4()后:
这里居然只到了 9 的位置,然后对比了_skipUtf8_3 和_skipUtf8_4,发现_skipUtf8_3 中_inputPtr 进行了两次自增:
_skipUtf8_4 也只进行了 2 次自增:
我们再次验证是否是 jackson1 中_skipUtf8_4 是否少执行了一次以下逻辑:
使用 jackson2 再次验证这个问题发现 jackson2 中逻辑:
发现在 jackson2 中多执行了一次,并且从 debug 结果来看 jackson2 中的_inputPtr 执行完以后变成了 10:
结论
自此可以看出是因为 jackson1 执行 skipstring 操作逻辑中,如果是 4 个 bytes 的特殊字符会少操作一次,导致下次读取的 byte 错误,从而抛出了异常,但是在 jackson2 中修复了这个 bug。
这个问题来源自:业务消费 kafka 消息默认使用 jackson1 反序列化后异常引发的问题,业务方在 bean 中只写了一个 getTextOfExt()方法,导致把 bean toJson 的时候将 bean 中 ext 的特殊字符引入到 textOfExt 中,但是 bean 中并没有 textOfExt 这个属性,于是 json 反序列化 bean 的时候因 bean 中不存在的属性 textOfExt 值中存在 4 个 bytes 的特殊字符,导致抛出异常。
当然根本原因还是 jackson1 对 4 个 byte 字符解析问题,但是也告诉我们在处理 json 问题不需要的属性方法最好还是不要写入需要序列化/反序列化的 bean 中亦或者使用注解屏蔽掉,尽可能保证 bean 的简单性以及 bean 中属性的有效性。
补充
这个 bug 是 jackson 编号[JACKSON-738],并在 2011.12.17 解决了这个 bug,在这之后发布的版本均修复了这个 bug。
查看了之后发布的版本:
>=1.8.7
>=1.9.3
>=2.0
均修复了这个问题,上述问题描述基于使用的 1.6.0 版本的 jackson 遇到的问题。
版权声明: 本文为 InfoQ 作者【BUG侦探】的原创文章。
原文链接:【http://xie.infoq.cn/article/d4da1f00595a57b03f722ffde】。文章转载请联系作者。
评论