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

相关推荐
Scott9999HH4 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社5 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海5 小时前
python 列表、元组、集合和字典
开发语言·python
二十雨辰6 小时前
[爬虫]-Urllib
爬虫·python
萧瑟余晖6 小时前
JDK 26 新特性详解
java·开发语言
马优晨7 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
玉鸯7 小时前
Agent Hook:在概率推理之上,为 Agent 叠加确定性控制
python·langchain·agent
weixin_446260858 小时前
HACO:面向动态部署环境的对冲式智能计算可靠多智能体调度框架
后端·python·flask
我的xiaodoujiao8 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest