Fastjson枚举反序列化:当字符串不是枚举常量名时,会发生什么?

我们知道,对外暴露的 HTTP RestAPI 接口通常使用 JSON 格式传输数据。服务端接收到数据后,会将 JSON 字符串反序列化为对应的请求实体对象。

我司灵工系统使用的是 Fastjson-1.2.83 作为序列化工具。在一次RestAPI开发过程中,我忽然产生一个好奇:当 VO 属性的类型是枚举(enum),而调用方传入的 JSON 字符串不是一个有效的枚举常量值时,Fastjson 会如何处理?

带着这个疑问,我决定一探究竟。

一、测试序幕:一个"意外"的异常

我使用系统内现有的 SourcePlatformEnum 枚举进行测试。

首先,我写了一段代码,将一个枚举实例序列化成 JSON 字符串:

java 复制代码
String jsonString = JSON.toJSONString(SourcePlatformEnum.YCX);
System.out.println(jsonString);

运行程序,输出结果为:"YCX"。这符合预期,Fastjson 默认将枚举序列化为其名称字符串。

接着,我尝试将这个字符串反序列化回枚举对象:

java 复制代码
String jsonString = "YCX";
System.out.println(JSON.parseObject(jsonString, SourcePlatformEnum.class));

这时,运行程序却意外地抛出了JSONException异常:

java 复制代码
com.alibaba.fastjson.JSONException: syntax error, pos 1, line 1, column 2YCX

    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1510)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1390)
    at com.alibaba.fastjson.serializer.StringCodec.deserialze(StringCodec.java:105)
    at com.alibaba.fastjson.serializer.StringCodec.deserialze(StringCodec.java:87)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:705)
    at com.alibaba.fastjson.JSON.parseObject(JSON.java:394)
    at com.alibaba.fastjson.JSON.parseObject(JSON.java:298)
    at com.alibaba.fastjson.JSON.parseObject(JSON.java:588)
    at com.levy.openapi.TestMain.test(TestMain.java:18)
    ...

问题出在哪里?

原来,错误在于 jsonString 的赋值。"YCX" 只是一个普通的 Java 字符串,并非合法的 JSON 字符串。在 JSON 格式中,字符串值必须由双引号包裹。

正确的写法应该是:String jsonString = "\"YCX\"";

这个小小的插曲给了我一个重要的提醒:在进行任何反序列化测试前,首先要确保输入的 JSON 格式是正确的。

二、正式测试:四种情况下的行为

修正了格式错误后,我使用fastjson-1.2.83系统地测试了四种常见情况,结果如下:

用例 输入的 JSON 字符串 Fastjson 反序列化后的 SourcePlatformEnum 值
Case 1 null null
Case 2 "" (空字符串) null
Case 3 "YCX" (有效的枚举常量名) SourcePlatformEnum.YCX
Case 4 "INVALID_VALUE" (无效的枚举常量名) null
Case 5 "null" (无效的枚举常量名) null
Case 6 "ycX" (大小写不一致) SourcePlatformEnum.YCX

测试结果非常明确:

  1. 当输入为 null 或空字符串时,反序列化结果为 null。
  2. 当输入是有效的枚举常量名(大小写不敏感)时,能正确反序列化为对应的枚举实例。
  3. 当输入是无效的枚举常量名 时,反序列化结果同样为 null,而不会抛出异常。这是Fastjson的默认行为。

一句话总结为:Fastjson 在枚举反序列化时,对非法值采取了 "静默返回 null" 的策略,而非抛出异常。

注:fastjson-1.2.83枚举反序列化器源码是com.alibaba.fastjson.parser.deserializer.EnumDeserializer。

三、如何权衡:API设计中能否使用枚举类型?

那么,在实际的 API 接口设计中,对于那些有对应枚举类的请求参数,能否使用枚举作为其数据类型呢?

我认为,关键在于如何理解并处理上面的 Case 4。

  • 如果某个参数是极少变化的、明确的、必传的 ,那么将其定义为枚举类型是非常合适 的。这本身就是一种强类型的契约,能清晰地告知调用方允许的取值范围。即使对方传了非法值,在服务端接收到的是一个 null,我们可以在业务校验中轻松捕获并返回明确的参数错误提示。

  • 而对于那些非必填的、不定期会有变化的参数,则可仍然使用基本Java类型。当然,如果不介意非法值被静默转换为 null,定义为枚举类型在代码可读性上也有其价值。

以我司商户API接口为例 :我们采用的是门面模式,即所有 API 共用一个 URL,通过必传的 funCode 参数来区分具体业务。这个 funCode 我们就将其定义为 FunCodeEnum 枚举类型。而如查询交易接口中的交易类型,这个可选参数可以为基本Java类型,这样当出现问题时,通过原始入参值更容易排查。

相关推荐
进击的明明4 分钟前
当AI开始“边想边干”:深入聊聊ReAct,以及如何用Python手搓一个简单Agent
python·面试·agent
全栈弄潮儿1 小时前
Python实战第8期:函数
后端·python·编程语言
卷无止境3 小时前
暗流与破局:AI时代的代码安全审查工具全景指南
后端·python
卷无止境5 小时前
一人公司的全栈选型指南:让 AI Agent 写得快,也让生意跑得稳
后端·python
WJ.Polar6 小时前
Java封装、继承、多态
java·开发语言
摇滚侠7 小时前
Java 中如何表示负数,有符号和无符号的区别,补码的计算规则,char byte short int long 的范围
java·开发语言
滴啦嘟啦哒7 小时前
【具身笔记】【π0.5 微调与仿真】五、在MuJoCo中实现可视化仿真
笔记·python·vla·具身
weixin_307779137 小时前
C++代码实现MATLAB中的fitrtree函数功能
开发语言·c++·算法·matlab
全栈练习生7 小时前
AI安全与红队测试
python·ai
爱读书的小胖7 小时前
Codewars:Rot13(C)解题分析
c语言·开发语言