奇怪的!Spring Boot 中的长值舍入问题

kan*_*rbk 3 java spring jackson spring-boot

当我尝试使用 Jackson 对象映射器将对象序列化为 JSON 时,它运行良好。

 {"id":1291741231928705024,"uuid":null,"email":"kannanrbk.r@gmail.com"}
Run Code Online (Sandbox Code Playgroud)

然而,当我尝试使用弹簧休息控制器访问它时。长值数字四舍五入,最后 3 位数字。

在此处输入图片说明

我在 stackoverflow 中阅读了现有问题,其中大多数建议将数据类型更改为字符串。但是我们在大多数地方使用了 Long 值引用,更改数据类型需要一些重构。

我做了初步分析:

  1. 我们正在使用杰克逊 ObjectMapper
  2. 从 Spring,它间接调用 MappingJackson2HttpMessageConverter
  3. 这个问题可能在 JSONParser 附近,它将任何数字视为双精度(15 位),然后四舍五入

有没有办法解决这个问题?

cac*_*co3 5

有没有办法解决这个问题?

Jackson/Java/Spring Boot 没有问题,但 JavaScript/Browser 没有问题。

试图重现这个问题我序列化了同一个对象并使用curl

$ curl localhost:8080
{"id":1291741231928705024,"uuid":null,"email":"kannanrbk.r@gmail.com"}
Run Code Online (Sandbox Code Playgroud)

此处编号已正确序列化。

在 Firefox查看的相同 json确实会截断

Firefox 中的截断值(JSON 选项卡)

但是,“原始数据”选项卡正确显示了数字:

Firefox 中显示的正确值(“原始数据选项卡”).

在 JavaScript1291741231928705024中不是安全整数(请参阅Number.isSafeInteger()):

Number.isSafeInteger(1291741231928705024);
false
Run Code Online (Sandbox Code Playgroud)

数字大于2^53 - 1所以它被四舍五入。JavaScript 中可能出现更令人困惑的情况:

> 1291741231928705024 === 1291741231928705022
true
Run Code Online (Sandbox Code Playgroud)

可能的解决方案

首先,检查您的客户是否存在此类问题。如果它可以安全地反序列化这些数字,那么您就安全了。

或者您可以longs序列化为Strings(正如您在问题中提到的),这是 Twitter 在其Twitter IDs (snowflake)文章中提出的建议 :

为了允许 Javascript 和 JSON 解析器读取 ID,Twitter 对象在使用 JSON 响应时包含任何 ID 的字符串版本。因此,Twitter API 中的状态、用户、直接消息、保存的搜索和其他 ID 在 JSON 响应中作为整数和字符串返回。