diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONConfig.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONConfig.java
index 70297df6f..af02fdf44 100644
--- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONConfig.java
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONConfig.java
@@ -15,6 +15,7 @@ package org.dromara.hutool.json;
import org.dromara.hutool.core.comparator.CompareUtil;
import org.dromara.hutool.core.convert.Converter;
import org.dromara.hutool.json.convert.JSONConverter;
+import org.dromara.hutool.json.writer.NumberWriteMode;
import java.io.Serializable;
import java.util.Comparator;
@@ -64,6 +65,10 @@ public class JSONConfig implements Serializable {
* 自定义的类型转换器,用于在getXXX操作中自动转换类型
*/
private Converter converter = JSONConverter.of(this);
+ /**
+ * Number写出模式
+ */
+ private NumberWriteMode numberWriteMode = NumberWriteMode.NORMAL;
/**
* 创建默认的配置项
@@ -257,6 +262,7 @@ public class JSONConfig implements Serializable {
/**
* 获取自定义的类型转换器,用于在序列化、反序列化操作中实现对象类型转换
+ *
* @return 转换器
*/
public Converter getConverter() {
@@ -265,9 +271,33 @@ public class JSONConfig implements Serializable {
/**
* 设置自定义的类型转换器,用于在序列化、反序列化操作中实现对象类型转换
+ *
* @param converter 转换器
*/
public void setConverter(final Converter converter) {
this.converter = converter;
}
+
+ /**
+ * 获取Number写出模式
+ *
+ * @return Number写出模式
+ * @since 6.0.0
+ */
+ public NumberWriteMode getNumberWriteMode() {
+ return numberWriteMode;
+ }
+
+ /**
+ * 设置数字写出模式
+ * 考虑到在JS或其他环境中,Number超过一定长度会丢失精度,因此针对Number类型值,可选写出规则
+ *
+ * @param numberWriteMode Number写出模式
+ * @return this
+ * @since 6.0.0
+ */
+ public JSONConfig setNumberWriteMode(final NumberWriteMode numberWriteMode) {
+ this.numberWriteMode = numberWriteMode;
+ return this;
+ }
}
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/NumberValueWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/NumberValueWriter.java
index 0b2336bcf..9fde4cc57 100644
--- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/NumberValueWriter.java
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/NumberValueWriter.java
@@ -22,6 +22,12 @@ import org.dromara.hutool.json.JSONConfig;
* @since 6.0.0
*/
public class NumberValueWriter implements JSONValueWriter {
+
+ /**
+ * JS中表示的数字最大值
+ */
+ private static final long JS_MAX_NUMBER = 9007199254740992L;
+
/**
* 单例对象
*/
@@ -39,7 +45,24 @@ public class NumberValueWriter implements JSONValueWriter {
public void write(final JSONWriter writer, final Number number) {
final JSONConfig config = writer.getConfig();
// since 5.6.2可配置是否去除末尾多余0,例如如果为true,5.0返回5
- final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros();
- writer.writeRaw(NumberUtil.toStr(number, isStripTrailingZeros));
+ final boolean isStripTrailingZeros = (null == config) || config.isStripTrailingZeros();
+ final String numberStr = NumberUtil.toStr(number, isStripTrailingZeros);
+
+ final NumberWriteMode numberWriteMode = (null == config) ? NumberWriteMode.NORMAL : config.getNumberWriteMode();
+ switch (numberWriteMode){
+ case JS:
+ if(number.longValue() > JS_MAX_NUMBER){
+ writer.writeQuoteStrValue(numberStr);
+ } else{
+ writer.writeRaw(numberStr);
+ }
+ break;
+ case STRING:
+ writer.writeQuoteStrValue(numberStr);
+ break;
+ default:
+ writer.writeRaw(numberStr);
+ break;
+ }
}
}
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/NumberWriteMode.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/NumberWriteMode.java
new file mode 100644
index 000000000..067eb21d3
--- /dev/null
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/NumberWriteMode.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.json.writer;
+
+/**
+ * Long写出模式
+ * 考虑到在JS或其他环境中,Long超过一定长度会丢失精度,因此针对Long类型值,可选写出规则
+ *
+ * @author Looly
+ * @since 6.0.0
+ */
+public enum NumberWriteMode {
+ /**
+ * 一般模式,所有Long值写出为普通数字,如{"value": 123456789}
+ */
+ NORMAL,
+ /**
+ * 浏览器中Javascript兼容模式,此模式下,如果Long输出长度大于
+ */
+ JS,
+ /**
+ * 所有Long类型的数字均转为字符串形式,如{"value": "123456789"}
+ */
+ STRING
+}
diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/writer/Issue3541Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/writer/Issue3541Test.java
new file mode 100644
index 000000000..9bbb05bef
--- /dev/null
+++ b/hutool-json/src/test/java/org/dromara/hutool/json/writer/Issue3541Test.java
@@ -0,0 +1,60 @@
+package org.dromara.hutool.json.writer;
+
+import lombok.Data;
+import org.dromara.hutool.json.JSONConfig;
+import org.dromara.hutool.json.JSONUtil;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class Issue3541Test {
+ @Test
+ void writeNumberJSTest() {
+ final Demo demo = new Demo();
+ // 超出长度
+ demo.setId(1227690722069581409L);
+ demo.setName("hutool");
+ final String jsonStr = JSONUtil.toJsonStr(demo, JSONConfig.of().setNumberWriteMode(NumberWriteMode.JS));
+ Assertions.assertEquals("{\"id\":\"1227690722069581409\",\"name\":\"hutool\"}", jsonStr);
+
+ // 未超出长度
+ demo.setId(1227690722069581L);
+ final String jsonStr2 = JSONUtil.toJsonStr(demo, JSONConfig.of().setNumberWriteMode(NumberWriteMode.JS));
+ Assertions.assertEquals("{\"id\":1227690722069581,\"name\":\"hutool\"}", jsonStr2);
+ }
+
+ @Test
+ void writeNumberStringTest() {
+ final Demo demo = new Demo();
+ // 超出长度
+ demo.setId(1227690722069581409L);
+ demo.setName("hutool");
+ final String jsonStr = JSONUtil.toJsonStr(demo, JSONConfig.of().setNumberWriteMode(NumberWriteMode.STRING));
+ Assertions.assertEquals("{\"id\":\"1227690722069581409\",\"name\":\"hutool\"}", jsonStr);
+
+ // 未超出长度
+ demo.setId(1227690722069581L);
+ final String jsonStr2 = JSONUtil.toJsonStr(demo, JSONConfig.of().setNumberWriteMode(NumberWriteMode.STRING));
+ Assertions.assertEquals("{\"id\":\"1227690722069581\",\"name\":\"hutool\"}", jsonStr2);
+ }
+
+ @Test
+ void writeNumberNormalTest() {
+ final Demo demo = new Demo();
+ // 超出长度
+ demo.setId(1227690722069581409L);
+ demo.setName("hutool");
+ final String jsonStr = JSONUtil.toJsonStr(demo, JSONConfig.of().setNumberWriteMode(NumberWriteMode.NORMAL));
+ Assertions.assertEquals("{\"id\":1227690722069581409,\"name\":\"hutool\"}", jsonStr);
+
+ // 未超出长度
+ demo.setId(1227690722069581L);
+ final String jsonStr2 = JSONUtil.toJsonStr(demo, JSONConfig.of().setNumberWriteMode(NumberWriteMode.NORMAL));
+ Assertions.assertEquals("{\"id\":1227690722069581,\"name\":\"hutool\"}", jsonStr2);
+ }
+
+ @Data
+ public static class Demo {
+ private Long id;
+ private String name;
+ }
+}