Fastjson枚举反序列化:当字符串不是枚举常量名时,会发生什么?
我们知道对外暴露的 HTTP RestAPI 接口通常使用 JSON 格式传输数据。服务端接收到数据后会将 JSON 字符串反序列化为对应的请求实体对象。我司灵工系统使用的是Fastjson-1.2.83作为序列化工具。在一次RestAPI开发过程中我忽然产生一个好奇当 VO 属性的类型是枚举(enum)而调用方传入的 JSON 字符串不是一个有效的枚举常量值时Fastjson 会如何处理带着这个疑问我决定一探究竟。一、测试序幕一个“意外”的异常我使用系统内现有的SourcePlatformEnum枚举进行测试。首先我写了一段代码将一个枚举实例序列化成 JSON 字符串String jsonString JSON.toJSONString(SourcePlatformEnum.YCX); System.out.println(jsonString);运行程序输出结果为YCX。这符合预期Fastjson 默认将枚举序列化为其名称字符串。接着我尝试将这个字符串反序列化回枚举对象String jsonString YCX; System.out.println(JSON.parseObject(jsonString, SourcePlatformEnum.class));这时运行程序却意外地抛出了JSONException异常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 1nullnullCase 2(空字符串)nullCase 3YCX(有效的枚举常量名)SourcePlatformEnum.YCXCase 4INVALID_VALUE(无效的枚举常量名)nullCase 5null(无效的枚举常量名)nullCase 6ycX(大小写不一致)SourcePlatformEnum.YCX测试结果非常明确当输入为null或空字符串时反序列化结果为null。当输入是有效的枚举常量名(大小写不敏感)时能正确反序列化为对应的枚举实例。当输入是无效的枚举常量名时反序列化结果同样为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类型这样当出现问题时通过原始入参值更容易排查。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2424302.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!