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类型,这样当出现问题时,通过原始入参值更容易排查。

相关推荐
Zenova EdgeOS6 小时前
工业网关重试机制:从固定间隔到指数退避的工程实战
开发语言·网络·php
长空任鸟飞_阿康6 小时前
三、《从零手撸 Agent》 · system prompt 与核心参数:调好你的旋钮
人工智能·python·ai·prompt
嘻哈baby6 小时前
Go 函数中的参数为什么不支持默认值?
java·开发语言·jvm
一晌小贪欢6 小时前
python-第29天:Python面向对象之多态与抽象类
开发语言·python·数据可视化·面向对象·python办公·python多态
Chester_19996 小时前
CSP202312C.树上搜索
开发语言·数据结构·c++·蓝桥杯·stl
Figo_Cheung7 小时前
Figo共振网络宇宙演化论(RNC) :从原初对称破缺到全息大和谐的演化路径研究
开发语言·php·量子计算
重生之我来学Python7 小时前
Git-SVN 混合开发,从入门到精通!
开发语言·git·svn·github
CoderYanger7 小时前
前端基础——JavaScript(基础语法)(下篇)
java·开发语言·前端·javascript·程序人生·面试·职场和发展
京师20万禁军教头7 小时前
39面向对象(高级)-设计模式
java·开发语言·设计模式
2601_962381587 小时前
ArcGIS+Python+AI赋能高标准农田建设项目审计提质增效
python·arcgis·ai·高标准农田审计·大数据审计