英文:
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值引用,更改数据类型需要一些重构。
我进行了初步分析:
- 我们正在使用Jackson
ObjectMapper
。 - 从Spring,它间接调用了
MappingJackson2HttpMessageConverter
。 - 这个问题可能出现在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.
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:
- We are using Jackson
ObjectMapper
- From Spring, it indirectly calls
MappingJackson2HttpMessageConverter
- 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 被截断了:
然而,“原始数据”选项卡显示数字正确:
在 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:
However the "Raw Data" tab displays the number correctly:
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 long
s as String
s (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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论