奇怪!在Spring Boot中出现了长整型数值截断问题。

huangapple go评论97阅读模式
英文:

Weird! Long value round off issue in spring boot

问题

当我尝试使用Jackson对象映射器将对象序列化为JSON时,它完美地工作。

{"id":1291741231928705024,"uuid":null,"email":"kannanrbk.r@gmail.com"}

然而,当我尝试使用Spring REST控制器访问它时,长整数的值会被四舍五入,最后3位。

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

我进行了初步分析:

  1. 我们正在使用Jackson ObjectMapper
  2. 从Spring,它间接调用了MappingJackson2HttpMessageConverter
  3. 这个问题可能出现在JSON解析器周围,它将任何数字都视为双精度(15位数字),然后四舍五入。

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

英文:

When I try to serialize an object to JSON using Jackson object mapper, it works perfectly.

 {"id":1291741231928705024,"uuid":null,"email":"kannanrbk.r@gmail.com"}

Whereas, when I try to access it using spring rest controller. The long value numbers are rounded off, the last 3 digits.

奇怪!在Spring Boot中出现了长整型数值截断问题。

I read existing questions in the stackoverflow, most of them suggest changing the datatype to string. But we used the Long value reference in most of the places, changing datatype will need some refactoring.

I did my initial analysis:

  1. We are using Jackson ObjectMapper
  2. From Spring, it indirectly calls MappingJackson2HttpMessageConverter
  3. This problem might be somewhere around the JSONParser, where it treats any number as a double (15 digits) and after that, it's rounded off

Is there any way to fix this issue?

答案1

得分: 5

Here's the translated content:

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

Jackson/Java/Spring Boot 没有问题,问题出在 JavaScript/浏览器上。

为了重现问题,我使用 curl 序列化了相同的对象,并获得了以下结果:

$ curl localhost:8080
{"id":1291741231928705024,"uuid":null,"email":"kannanrbk.r@gmail.com"}

这里的数字被正确序列化了。

在 Firefox 中查看的相同 JSON 被截断了

奇怪!在Spring Boot中出现了长整型数值截断问题。

然而,“原始数据”选项卡显示数字正确:

奇怪!在Spring Boot中出现了长整型数值截断问题。

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

Number.isSafeInteger(1291741231928705024);
false

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

> 1291741231928705024 === 1291741231928705022
true

可能的解决方案

首先,检查您的客户端是否能够安全地反序列化这种数字。如果可以的话,那么您是安全的。

或者,您可以将 long 序列化为 String(正如您在问题中提到的),这是 Twitter 在其 Twitter IDs (snowflake) 文章中提出的解决方案:

> 为了让 JavaScript 和 JSON 解析器能够读取这些 ID,Twitter 对象在使用 JSON 响应时会同时返回整数和字符串版本的 ID。因此,在 Twitter API 中的状态、用户、直接消息、保存搜索等 ID 在 JSON 响应中都以整数和字符串的形式返回。

英文:

> Is there any way to fix this issue?

There is no problem with Jackson/Java/Spring Boot, but with JavaScript/Browser.

Trying to reproduce the issue I serialized the same object and got this using curl:

$ curl localhost:8080
{"id":1291741231928705024,"uuid":null,"email":"kannanrbk.r@gmail.com"}

Here the number is correctly serialized.

The same json viewed in Firefox does truncate:

奇怪!在Spring Boot中出现了长整型数值截断问题。

However the "Raw Data" tab displays the number correctly:

奇怪!在Spring Boot中出现了长整型数值截断问题。.

In JavaScript 1291741231928705024 is not safe integer (see Number.isSafeInteger()):

Number.isSafeInteger(1291741231928705024);
false

The number is greater than 2^53 - 1 so it gets rounded. Even more confusing situations are possible in JavaScript:

> 1291741231928705024 === 1291741231928705022
true

Possible solution

First of all check your client against this kind of problems. If it can safely deserialize such numbers then you're safe.

Or you can serialize longs as Strings (as you mentioned in the question), this is what Twitter proposes in its Twitter IDs (snowflake) article:

> To allow Javascript and JSON parsers to read the IDs, Twitter objects include a string version of any ID when responding with JSON. Status, User, Direct Message, Saved Search and other IDs in the Twitter API are therefore returned as both an integer and a string in JSON responses.

答案2

得分: 0

尝试使用 bigInt 作为您的主键。

英文:

Try with bigInt for your primary key

huangapple
  • 本文由 发表于 2020年8月12日 00:13:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/63362205.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定