diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/RegisterConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/RegisterConverter.java
index 8d9112eb9..89926d124 100644
--- a/hutool-core/src/main/java/cn/hutool/core/convert/RegisterConverter.java
+++ b/hutool-core/src/main/java/cn/hutool/core/convert/RegisterConverter.java
@@ -69,6 +69,7 @@ import java.util.concurrent.atomic.AtomicReference;
* @since 6.0.0
*/
public class RegisterConverter implements Converter, Serializable {
+ private static final long serialVersionUID = 1L;
/**
* 默认类型转换器
diff --git a/hutool-http/src/test/java/cn/hutool/http/RestTest.java b/hutool-http/src/test/java/cn/hutool/http/RestTest.java
index 588a03372..8a5da21fe 100644
--- a/hutool-http/src/test/java/cn/hutool/http/RestTest.java
+++ b/hutool-http/src/test/java/cn/hutool/http/RestTest.java
@@ -17,7 +17,7 @@ public class RestTest {
@Test
public void contentTypeTest() {
final HttpRequest request = HttpRequest.post("http://localhost:8090/rest/restTest/")//
- .body(JSONUtil.createObj()
+ .body(JSONUtil.ofObj()
.set("aaa", "aaaValue")
.set("键2", "值2").toString());
Assert.assertEquals("application/json;charset=UTF-8", request.header("Content-Type"));
@@ -27,7 +27,7 @@ public class RestTest {
@Ignore
public void postTest() {
final HttpRequest request = HttpRequest.post("http://localhost:8090/rest/restTest/")//
- .body(JSONUtil.createObj()
+ .body(JSONUtil.ofObj()
.set("aaa", "aaaValue")
.set("键2", "值2").toString());
Console.log(request.execute().body());
@@ -36,7 +36,7 @@ public class RestTest {
@Test
@Ignore
public void postTest2() {
- final String result = HttpUtil.post("http://localhost:8090/rest/restTest/", JSONUtil.createObj()//
+ final String result = HttpUtil.post("http://localhost:8090/rest/restTest/", JSONUtil.ofObj()//
.set("aaa", "aaaValue")
.set("键2", "值2").toString());
Console.log(result);
@@ -47,7 +47,7 @@ public class RestTest {
public void getWithBodyTest() {
final HttpRequest request = HttpRequest.get("http://localhost:8888/restTest")//
.header(Header.CONTENT_TYPE, "application/json")
- .body(JSONUtil.createObj()
+ .body(JSONUtil.ofObj()
.set("aaa", "aaaValue")
.set("键2", "值2").toString());
Console.log(request.execute().body());
@@ -60,7 +60,7 @@ public class RestTest {
// Charles代理
.setHttpProxy("localhost", 8888)
.header("Access-Token","")
- .body(JSONUtil.createObj()
+ .body(JSONUtil.ofObj()
.set("advertiser_ids", new Long[] {1690657248243790L})
.set("fields", new String[] {"id", "name", "status"}).toString());
Console.log(request);
diff --git a/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java b/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java
index 9681e2ec2..ad9f60a3f 100644
--- a/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java
+++ b/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java
@@ -27,7 +27,7 @@ public class SimpleServerTest {
)
// 返回JSON数据测试
.addAction("/restTest", (request, response) -> {
- final String res = JSONUtil.createObj()
+ final String res = JSONUtil.ofObj()
.set("id", 1)
.set("method", request.getMethod())
.set("request", request.getBody())
diff --git a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java
index 74c508e7d..f0c448f90 100755
--- a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java
+++ b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java
@@ -1,7 +1,9 @@
package cn.hutool.json;
import cn.hutool.core.bean.copier.CopyOptions;
+import cn.hutool.core.codec.HexUtil;
import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.map.CaseInsensitiveLinkedMap;
import cn.hutool.core.map.CaseInsensitiveTreeMap;
@@ -11,9 +13,12 @@ import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjUtil;
-import cn.hutool.json.convert.JSONConverter;
+import cn.hutool.json.convert.JSONConverterOld;
import cn.hutool.json.serialize.JSONString;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.time.temporal.TemporalAccessor;
@@ -144,7 +149,7 @@ public final class InternalJSONUtil {
} else if (ArrayUtil.isArray(value)) {
return new JSONArray(value).toString();
} else {
- return JSONUtil.quote(value.toString());
+ return quote(value.toString());
}
}
@@ -255,7 +260,88 @@ public final class InternalJSONUtil {
.setTransientSupport(config.isTransientSupport())
// 使用JSON转换器
.setConverter((type, value) ->
- JSONConverter.convertWithCheck(type, value, null, config.isIgnoreError()));
+ JSONConverterOld.convertWithCheck(type, value, null, config.isIgnoreError()));
+ }
+
+ /**
+ * 对所有双引号做转义处理(使用双反斜杠做转义)
+ * 为了能在HTML中较好的显示,会将</转义为<\/
+ * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
+ *
+ * @param string 字符串
+ * @return 适合在JSON中显示的字符串
+ */
+ public static String quote(final String string) {
+ return quote(string, true);
+ }
+
+ /**
+ * 对所有双引号做转义处理(使用双反斜杠做转义)
+ * 为了能在HTML中较好的显示,会将</转义为<\/
+ * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
+ *
+ * @param string 字符串
+ * @param isWrap 是否使用双引号包装字符串
+ * @return 适合在JSON中显示的字符串
+ * @since 3.3.1
+ */
+ public static String quote(final String string, final boolean isWrap) {
+ return quote(string, new StringWriter(), isWrap).toString();
+ }
+
+ /**
+ * 对所有双引号做转义处理(使用双反斜杠做转义)
+ * 为了能在HTML中较好的显示,会将</转义为<\/
+ * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
+ *
+ * @param str 字符串
+ * @param writer Writer
+ * @return Writer
+ * @throws IORuntimeException IO异常
+ */
+ public static Writer quote(final String str, final Writer writer) throws IORuntimeException {
+ return quote(str, writer, true);
+ }
+
+ /**
+ * 对所有双引号做转义处理(使用双反斜杠做转义)
+ * 为了能在HTML中较好的显示,会将</转义为<\/
+ * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
+ *
+ * @param str 字符串
+ * @param writer Writer
+ * @param isWrap 是否使用双引号包装字符串
+ * @return Writer
+ * @throws IORuntimeException IO异常
+ * @since 3.3.1
+ */
+ public static Writer quote(final String str, final Writer writer, final boolean isWrap) throws IORuntimeException {
+ try {
+ return doQuote(str, writer, isWrap);
+ } catch (IOException e) {
+ throw new IORuntimeException(e);
+ }
+ }
+
+ /**
+ * 转义显示不可见字符
+ *
+ * @param str 字符串
+ * @return 转义后的字符串
+ */
+ public static String escape(final String str) {
+ if (StrUtil.isEmpty(str)) {
+ return str;
+ }
+
+ final int len = str.length();
+ final StringBuilder builder = new StringBuilder(len);
+ char c;
+ for (int i = 0; i < len; i++) {
+ c = str.charAt(i);
+ builder.append(escape(c));
+ }
+ return builder.toString();
}
/**
@@ -286,4 +372,82 @@ public final class InternalJSONUtil {
}
return rawHashMap;
}
+
+ // --------------------------------------------------------------------------------------------- Private method start
+ /**
+ * 对所有双引号做转义处理(使用双反斜杠做转义)
+ * 为了能在HTML中较好的显示,会将</转义为<\/
+ * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
+ *
+ * @param str 字符串
+ * @param writer Writer
+ * @param isWrap 是否使用双引号包装字符串
+ * @return Writer
+ * @throws IOException IO异常
+ * @since 3.3.1
+ */
+ private static Writer doQuote(final String str, final Writer writer, final boolean isWrap) throws IOException {
+ if (StrUtil.isEmpty(str)) {
+ if (isWrap) {
+ writer.write("\"\"");
+ }
+ return writer;
+ }
+
+ char c; // 当前字符
+ final int len = str.length();
+ if (isWrap) {
+ writer.write('"');
+ }
+ for (int i = 0; i < len; i++) {
+ c = str.charAt(i);
+ switch (c) {
+ case '\\':
+ case '"':
+ writer.write("\\");
+ writer.write(c);
+ break;
+ default:
+ writer.write(escape(c));
+ }
+ }
+ if (isWrap) {
+ writer.write('"');
+ }
+ return writer;
+ }
+
+ /**
+ * 转义不可见字符
+ * 见:https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF
+ *
+ * @param c 字符
+ * @return 转义后的字符串
+ */
+ private static String escape(final char c) {
+ switch (c) {
+ case '\b':
+ return "\\b";
+ case '\t':
+ return "\\t";
+ case '\n':
+ return "\\n";
+ case '\f':
+ return "\\f";
+ case '\r':
+ return "\\r";
+ default:
+ if (c < StrUtil.C_SPACE || //
+ (c >= '\u0080' && c <= '\u00a0') || //
+ (c >= '\u2000' && c <= '\u2010') || //
+ (c >= '\u2028' && c <= '\u202F') || //
+ (c >= '\u2066' && c <= '\u206F')//
+ ) {
+ return HexUtil.toUnicodeHex(c);
+ } else {
+ return Character.toString(c);
+ }
+ }
+ }
+ // --------------------------------------------------------------------------------------------- Private method end
}
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSON.java b/hutool-json/src/main/java/cn/hutool/json/JSON.java
index ce13eb351..79e510951 100755
--- a/hutool-json/src/main/java/cn/hutool/json/JSON.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSON.java
@@ -1,7 +1,7 @@
package cn.hutool.json;
import cn.hutool.core.bean.BeanPath;
-import cn.hutool.json.convert.JSONConverter;
+import cn.hutool.json.convert.JSONConverterOld;
import java.io.Serializable;
import java.io.StringWriter;
@@ -169,6 +169,6 @@ public interface JSON extends Cloneable, Serializable {
* @since 4.3.2
*/
default T toBean(final Type type) {
- return JSONConverter.jsonConvert(type, this, getConfig());
+ return JSONConverterOld.jsonConvert(type, this, getConfig());
}
}
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java
index 69e0886da..29fcd1cb3 100755
--- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java
@@ -8,7 +8,7 @@ import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.text.StrJoiner;
import cn.hutool.core.util.ObjUtil;
-import cn.hutool.json.convert.JSONConverter;
+import cn.hutool.json.convert.JSONConverterOld;
import cn.hutool.json.mapper.ArrayMapper;
import cn.hutool.json.serialize.JSONWriter;
@@ -195,7 +195,7 @@ public class JSONArray implements JSON, JSONGetter, List