Fastjson 很快,但不适合我....

Posted Java技术栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fastjson 很快,但不适合我....相关的知识,希望对你有一定的参考价值。

作者:nyingping
来源:juejin.cn/post/7215886869199863869

记者:大爷您有什么特长呀?

FastJson:我很快。

记者:23423 乘以 4534 等于多少?

FastJson:等于 2343.

记者:??

FastJson:你就说快不快吧!

这个略显马丽苏的标题,各位看官将就着看吧。主要是怕被喷。FastJson 真的很好,我用不用我喜不喜欢的,太不重要了,我只是觉得不适合我而已。

话说以前 Gson 用得好好的,同事极力推荐我使用 FastJson,说很快云云。尽管我们的系统根本感知不出来这点速度差异。

之前也听说 FastJson 爆出来什么重大漏洞,但对我们基本没什么影响,所以这一点倒是没什么偏见。

然后在一个新项目上,脑抽抽,把 Gson 换成了 FastJson,Spring Boot 默认支持的 Jackson 换成了 FastJson。

然后就开始遇到了一些问题。先声明,这真不是尬黑,为了文章效果,故意网上扒些黑料拼凑起来,本文所提到的问题,都来源于本人最近项目的真实经历。

推荐一个开源免费的 Spring Boot 最全教程:

https://github.com/javastacks/spring-boot-best-practice

dateformat 优先级

本来是一个风和日丽的下午,一个非常简单的改动需求。接口返回的时间只需要年月日日期类型不需要时分秒。因为我配置全局时间格式化为yyyy-MM-dd HH:mmss,于是我愉快的在 javabean 的属性上加了个注解。

本地测试一下,没问题,提交到测试环境,搞定,完美。

然后就接到产品的疑问,改动呢?

我登上去看了一下,唉,没改到啊,日期还是带了时分秒。我大意了啊,这么小的改动,又是在测试环境,就没加验证。

那么现在的直接问题是:FastJson 关于时间配置在局部的配置没有生效,使用的还是全局配置。

现象是,开发环境 Windows 上没有问题,测试环境 Linux 上出现了问题。两者有什么区别呢?系统问题?

既然怀疑是两个系统导致的问题,那么就在 idea 里模拟一下 linux 系统。在 VM options 添加 -Dos.name=linux

这不能完全模拟 linux 系统,只针对通过System.getproperty("os.name")来判断当前系统做某些操作的时候有用。

通过这种方式没复现,我又想到了远程调试。

一阵操作猛如虎,远程调试倒是能进断点,只是断点进不了第三方 jar 包的源码。等于白搞。

得,还是回到源码吧。拉下源码,断点,观察 JSONSerializer 类,主要是writeWithFormat方法。没有发现问题。

因为怀疑是系统导致的,在源码中搜索\'linux\'\'unix\'关键字,没有发现。断点整个流程重点观察了一下这部份也没有发现问题。

突然在 JSONSerializer.dateFormatPattern上发现了这段注释。

这部份涉及到了调整 dateformat 的问题,重点在这个#1868,这通常是 github 的问题编号。

1.对于开源项目来说,解决了 BUG,通常会把问题编号放到注释里面去。前提是注释有必要。通过问题编号可以看到问题的前因后果。

2.通常来说,对于 github 开源项目都有 issue 区,拿着这个到编号直接到 issue 一搜就能搜到。

3.但也有一些项级项目,如 spark,flink 是没有 issue 区的,它们的类型问题发现描述追踪都使用 jira 平台。如:

https://issues.apache.org/jira/browse/SPARK-38349

在提交 PR 的时候标题也严格按照[jira 编号][spark 子模块(如core/sql) title]的规则来。

所以拿着这个编号到issue区,不管有没有issue区,也都可以直接到pullrequest区直接搜索,就算 PR 标题里没有问题编号,PR 描述肯定也是有的,只要是有严格 PR 流程的开源项目。

所以这个问题在这里:

https://github.com/alibaba/fastjson/issues/1868

相应的 PR 在这里:

https://github.com/alibaba/fastjson/pull/2706

通过 ISSUES 描述的已知信息,可以看出他遇到的问题跟我是一样的,而这个问题早在 2018 年就提出了。但问题描述不太专业,没有涉及到环境以及最重要的 FastJson 的版本问题。

而通过 PR 可知,这个问题最终在 2020 才解决,期间仅在 ISSUES 区提出的相同问题就有 #1868 #1968 #2029 #24524 个。

解决问题的版本为:1.2.72.

这个信息很关键。我对照了我开发环境的版本,是高于 1.2.72 的,所以没有出现测试环境的问题。

所以,柯南告诉我们,排除了所有可能性,剩下的哪怕再可笑,也是最终问题所在。

那就是,测试环境所用的 FastJson 版本是低于 1.2.72 的。

这种可能性是存在的,因为我们用的是 maven 打代码包,依赖包单独存在。

我最终在测试环境的依赖包目录下发现了两个 Fastjson 包,果然不出所料,有一个 1.2.53 的低版本,它就是罪魁祸首。

所以,最终这个问题有相当大的程度是由于我们团队自身问题引发的。但通过解决这个问题的过程也发现了一些有意思的情况。

首先,FastJson 在某一个版本为什么会引发这个问题。它肯定是某个 PR 改出问题的,rv,testcase 覆盖没有到位。

其次,从试图解决这个问题的 3 个 PR 的时间线,分别在 2018 年,2019 年,2020 年。说明,FastJson 这个项目的 contributor 看起来有百来人,但其中过于依赖其中某 1 个或者某些主力人员。精力有限,某些优先级不那么高的 BUG 只能放任。

同时这个项目的荣誉感并没有那么高(或者叫并没有那么吸引高手),它并不是 Apache 顶级项目,要是其它诸如 Spark、Flink、Spring,哪怕是 Dubbo 呢,很想象这些项目会有一个并不算复杂的 BUG 悬而未决长达 3 年时间。在这些顶级开源项目,大家都是拼了老命的想找些 BUG 来提交 PR。

当然,以上只是我个人的一点猜测。

复盘,遇到 FastJson 的问题,一开始就应该奔着 github 的 issues 区,它大概率已经被前人踩坑了。

$ref 循环引用问题

以上测试接口返回前端什么?

我现在并不知道什么循环引用检测,这时候它是我的知识盲区。此时,我观察到的现象是,youngchildren两个 list 对象中均引用指向了王麻子这个对象。然后,在第 2 次children引用的时候它在序列化的时候直接指向了第 1 个young里相应对象引用。当然遇到这个问题的时候,我在仔细观察排除了非 fastjson 的问题以后,这次我学聪明了,我直接来到了 Github 的 issues 区,搜索$ref

果然有很多同道中人,近 150 个问题,从时间上来看还挺新鲜。我点击了 closed,既然关闭了,那肯定解决了吧。

我点进了 closed 区第一个问题,然后作者让升级到 fastjson2。???

如果我没有理解错,FastJson 和 FastJson2 可不是两个版本的区别,是两个项目也!据说 API 也有兼容性问题。直接这样升级过去,谈何容易!

我觉得这也是个槽点,FastJson 好像并没有一个稳定维护的版本,遇到问题总是在升级,升级的过程中也没做好质量控制,又引入了新的问题。

还是在当前项目寻求解决方法吧,哪怕升版本也好啊。终于在另一个问题下面找到了问题所在以及解决方案。

https://github.com/alibaba/fastjson/issues/3643

我现在知道这是由于循环引用检测引起的。通过设置SerializerFeature.DisableCircularReferenceDetect可以避免这个问题。

但是,我的代码其实并没有循环引用啊,只是两个子对象引用了同一个对象而已。这算什么?误伤吗?

更重要的,一些控制权应该在使用者手里?

比如,当前这个循环引用在序列化会出的问题,应该是用户手动去开启,而不是默认给用户开启。在优先级上,全局应该关闭,在有循环引用的地方,让用户选择局部开启。

现在我的前端并没有使用 FastJson,面对"$ref":"$.result.young[1]"这种文本,它能解析吗?它不能呀。

我测试了一下,好像使用 FastJson 也并不能解析回来:

:经提醒,这里应使用完整报文解析,经测试,确实可以。感谢提醒!

更可怕的问题是,刚好在测试环节有两个子对象引用了同一个对象,被我提前发现了。如果测试环境没有这样的情况,在生产环境刚好遇到了呢?那就是生产事故了呀。

本来是一个挺好的设计点,能起到锦上添花的作用,但它却可能暴雷,这是好心办坏事。

同样的,还有SerializerFeature.WriteMapNullValue。如果一个字段值为null,fastjson 默认就不返回该字段了。本来前后端约定好,如果为null就怎样处理的逻辑,可能在生产环境中突然暴雷啊。

就像WriteNullListAsEmpty就很好,不错的设计点,如果返回的 list 为null的时候,用户可以选择让它序列化为[],但它也不是默认开启的呀,给了用户额外的选择权,对吧。

总结

写到这里的时候,我是真心觉得 FastJson 有比竞品有些特色的地方。这真不是为了所谓的客观公正,非要负面写多点,再搞点正面的。

为了写文章,那肯定要去试验,得把竞品也拿出来测试一下,一测试发现并不是 FastJson 独有的,尴尬!

但我还是那句话,不管你信不信,对于开源项目,特别是这样一个广泛使用的开源项目,肯定有非常值得学习的地方。一个开源项目,如果整天拿着显微镜去观察,那肯定能找出不少毛病。

这里稍微总结一下本文的信息点。并不一定是某个具体 BUG,而是通过这个 BUG,解决这个 BUG 背后所展现出来的 FastJson 的信息或趋势。

  1. reviewtestcase 覆盖不是很到位
  2. contributor 看起来很多,但严重依赖主力人员。而主力精力有限,某些优先级不那么高的 BUG 只能放任。
  3. 这个项目的荣誉感并没有那么高,或者叫并没有那么吸引高手)。
  4. 有些功能点应该把控制主动权交给用户,如 DisableCircularReferenceDetectWriteMapNullValue 等。默认开启非常容易导致线上暴雷。
  5. 作者已经全面转向 fastjosn2,而且哪怕在这之前,对于 fastjson 没有一个稳定维护的版本,不断升级,不断引入新问题。

祝愿 fastjson2 越来越好,不要步 struts2 的后尘。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

iOS 应用程序在 Apple 审批过程中崩溃,但不适合我

【中文标题】iOS 应用程序在 Apple 审批过程中崩溃,但不适合我【英文标题】:iOS App crashes on Apple approval process but not for me 【发布时间】:2013-10-08 08:57:54 【问题描述】:

过去两周我一直在尝试更新一个 iOS 客户端应用程序,不幸的是它被拒绝了两次,因为 Apple 说它在 iOS7 上崩溃了。 Apple 已向我发送以下崩溃报告。

Incident Identifier: C213974C-73E2-42C4-A2AA-E4C2A454319E
CrashReporter Key:   2c5d5176cc4387265bd86c427bf138d2b0acfe38
Hardware Model:      xxx
Process:             Twlight Sports [502]
Path:                /var/mobile/Applications/2B9ED7B5-787E-48ED-AAEC-3DEF87A86C67/Twlight Sports.app/Twlight Sports
Identifier:          com.twilightsports.twilightsports
Version:             1.2 (1.2)
Code Type:           ARM (Native)
Parent Process:      launchd [1]

Date/Time:           2013-09-27 15:22:18.784 -0700
OS Version:          iOS 7.0 (11A465)
Report Version:      104

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000000e7ffdefe
Triggered by Thread:  0

Dyld Error Message:
  Library not loaded: /Developer/Library/Frameworks/SenTestingKit.framework/SenTestingKit
  Referenced from: /var/mobile/Applications/2B9ED7B5-787E-48ED-AAEC-3DEF87A86C67/Twlight Sports.app/Twlight Sports
  Reason: image not found
  Dyld Version: 324

Binary Images:
0x2beed000 - 0x2bf0d78a dyld armv7  <b37cba000c7d3f8ea414f060d45ce144> /usr/lib/dyld

我删除了项目中对SenTestingKit 的所有引用,并再次提交了应用更新。 一周后,我收到了来自 Apple 的完全相同的崩溃报告。

然后,我创建了一个 AdHoc,与我发送给 Apple 的二进制文件非常相似,并将其部署到我的 iPhone 4S 和 iPad 2 上。这两款设备都可以正常工作而不会崩溃。

我已经对拒绝提出上诉,希望 Apple 会再次测试该应用程序,但他们拒绝了上诉,只是说它仍在崩溃并且不再提供任何帮助。目前我很茫然,因为我无法复制崩溃,因此无法修复它。

我的工作区中还运行着 CocoaPods,并安装了 Kiwi TDD pod。这引用了但是 Pods Build 目标在其 Link Binary With Libraries 中没有 SenTestingKit.framework@

【问题讨论】:

仅凭此描述,我无法为您提供任何帮助。您可能需要发布一些 Xcode 构建设置和构建包的屏幕截图 不清楚您希望这里的任何人如何帮助您处理这些有限的信息。 你在iOS7上也测试过吗? similar issue 为什么要将测试框架链接到您的应用程序中?它们仅属于测试目标。搜索“cocoapods target Exclusive”看看如何。 【参考方案1】:

您可以在重新提交之前使用otool 检查您的应用二进制文件,以了解它是否链接SenTestingKitotool -L 将列出 Mach-O 二进制文件的链接库。

例如 Xcode 链接:

% otool -L /Applications/Xcode.app/Contents/MacOS/Xcode                                                                             
/Applications/Xcode.app/Contents/MacOS/Xcode:
    /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 20.0.0)
    @rpath/DVTFoundation.framework/Versions/A/DVTFoundation (compatibility version 1.0.0, current version 3532.0.0)
    @rpath/DVTKit.framework/Versions/A/DVTKit (compatibility version 1.0.0, current version 3546.0.0)
    @rpath/IDEFoundation.framework/Versions/A/IDEFoundation (compatibility version 1.0.0, current version 3569.0.0)
    @rpath/IDEKit.framework/Versions/A/IDEKit (compatibility version 1.0.0, current version 3591.0.0)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1052.0.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
    /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1247.0.0)

您可以通过创建 App Store 构建,将 .ipa 复制到某个文件夹中,在您的应用商店二进制文件上运行它。将.ipa 重命名为.zip。打开.zip 文件,然后在应用程序内的二进制文件上运行otool -L,可能是这样的:(这是iBooks)

% cd iBooks\ 3.1.3/Payload/iBooks.app                                                                                                     
% otool -L iBooks                                                                                                                         
iBooks:
    /usr/lib/liblockdown.dylib (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/StoreKit.framework/StoreKit (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/PrivateFrameworks/Celestial.framework/Celestial (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/AssetsLibrary.framework/AssetsLibrary (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 992.0.0)
    /System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 2372.0.0)
    /System/Library/Frameworks/CoreGraphics.framework/CoreGraphics (compatibility version 64.0.0, current version 600.0.0)
    /System/Library/PrivateFrameworks/iTunesStoreUI.framework/iTunesStoreUI (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/MediaPlayer.framework/MediaPlayer (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/PrivateFrameworks/iTunesStore.framework/iTunesStore (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/PrivateFrameworks/StoreServices.framework/StoreServices (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/QuartzCore.framework/QuartzCore (compatibility version 1.2.0, current version 1.8.0)
    /System/Library/PrivateFrameworks/GraphicsServices.framework/GraphicsServices (compatibility version 1.0.0, current version 14.0.0)
    /System/Library/PrivateFrameworks/AppSupport.framework/AppSupport (compatibility version 1.0.0, current version 29.0.0)
    /System/Library/PrivateFrameworks/WebKit.framework/WebKit (compatibility version 1.0.0, current version 536.26.0)
    /System/Library/Frameworks/CoreData.framework/CoreData (compatibility version 1.0.0, current version 419.0.0)
    /System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore (compatibility version 1.0.0, current version 536.26.0)
    /System/Library/Frameworks/CFNetwork.framework/CFNetwork (compatibility version 1.0.0, current version 609.0.0)
    /System/Library/PrivateFrameworks/WebCore.framework/WebCore (compatibility version 1.0.0, current version 536.26.0)
    /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
    /System/Library/PrivateFrameworks/Bom.framework/Bom (compatibility version 2.0.0, current version 189.0.0)
    /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)
    /System/Library/Frameworks/CoreText.framework/CoreText (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libAccessibility.dylib (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/MobileCoreServices.framework/MobileCoreServices (compatibility version 1.0.0, current version 40.0.0)
    /usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 9.6.0)
    /System/Library/Frameworks/MessageUI.framework/MessageUI (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/AVFoundation.framework/AVFoundation (compatibility version 1.0.0, current version 2.0.0)
    /System/Library/Frameworks/ImageIO.framework/ImageIO (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration (compatibility version 1.0.0, current version 499.0.0)
    /System/Library/Frameworks/Security.framework/Security (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/AudioToolbox.framework/AudioToolbox (compatibility version 1.0.0, current version 359.0.0)
    /usr/lib/libicucore.A.dylib (compatibility version 1.0.0, current version 49.1.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 56.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 173.8.0)
    /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 793.0.0)

然后在列表中查找 SenTestingKit 以获取您应用的二进制文件。

【讨论】:

感谢您的回复,如果问题再次出现,我会试一试【参考方案2】:

您发布的信息非常有限,但我将从以下步骤开始:

    您对硬件型号进行了 xxx 处理,但崩溃可能是特定于硬件的,并且可能仅发生在您未测试的硬件上。 与操作系统相同,您可能已在 7.0.1 或 7.0.2 上进行过测试,但根据崩溃报告,它发生在 7.0 上,因此请确保您对此进行了测试。 帮自己一个忙,开始使用 TestFlight 进行崩溃报告,您将不必依赖他人向您发送崩溃报告,而是会自动将崩溃报告发送给您并象征性地发送给您。 在硬件上测试应用时,请确保测试发布配置。优化发布构建时可能会出现很多问题,因此测试发布是这里唯一明智的选择。 您在验证期间是否收到任何警告?如果是,也许您应该认真对待它们?

我假设应用程序没有启动,但在启动时崩溃。在这种情况下,我不确定 TestFlight 是否会对您有很大帮助,相反,我认为您的 Debug 和 Release 配置之间可能存在差异,导致稍后使用 SenTestKit。

【讨论】:

感谢您的回复,我已经尝试使用 Testflight 进行 AdHoc 部署,但它仍然没有崩溃,我不确定如何将我的 7.0.2 设备降级回 7.0,如果这是可能我可以试试。我得到的唯一警告是我没有提供 iOS7 推荐的 150x150 图标,我也会在 iPad 3 上尝试【参考方案3】:

嗯.....

为了解决这个问题,我基本上不得不从我的工作区中删除 CocoaPods,删除测试目标和测试方案,我上周四重新提交了应用程序,今天刚刚被接受。

这是一次非常绝望的修复尝试,我认为罪魁祸首是 Apple 正在我的项目上运行我没有正确设置的测试方案。移除 Kiwi Cocoapods 后,看起来它修复了请求 SenTestingKit 框架的任何内容

【讨论】:

很高兴听到它被批准了,同时很遗憾你不得不删除这些东西,因为我很确定你提交了应用程序的 DEBUG 版本。如果是这种情况,将存档方案更改为使用“发布”而不是“调试”就足够了。希望这对您将来有所帮助。 我建议将此信息添加到您帖子的末尾作为更新,而不是作为答案。【参考方案4】:

我遇到了类似的问题,即应用程序在我的设备上运行良好但被苹果拒绝。 这是说包中的某些文件已损坏。 当我为所有用户设置读、写和执行权限并再次提交应用程序时,它被批准了。 这可能是您的情况的原因之一。请尝试设置权限并重新创建二进制文件并提交。

【讨论】:

感谢您的回复,您可以在 XCode 中设置此权限吗,我不确定在哪里查看 这些是您可以通过 chmod -R 777 设置的权限。和我们在linux中设置的类似

以上是关于Fastjson 很快,但不适合我....的主要内容,如果未能解决你的问题,请参考以下文章

“这么快”的FastJson,为何又要被抛弃

iOS 应用程序在 Apple 审批过程中崩溃,但不适合我

怎么将json文件转成xml文件

Gson 和 Fastjson 你不知道的事

java-com.alibaba.fastjson快速处理json字符串转成list类型

我应该使用 .NET Core 还是 .NET 5? [关闭]