diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java index 317b66212..fc1afd4d9 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java @@ -29,8 +29,6 @@ import org.dromara.hutool.core.text.split.SplitUtil; import org.dromara.hutool.json.serialize.GlobalSerializeMapping; import org.dromara.hutool.json.serialize.JSONDeserializer; import org.dromara.hutool.json.serialize.JSONStringer; -import org.dromara.hutool.json.writer.GlobalValueWriterMapping; -import org.dromara.hutool.json.writer.JSONValueWriter; import java.io.IOException; import java.io.StringWriter; @@ -262,23 +260,6 @@ public final class InternalJSONUtil { return rawHashMap; } - /** - * 根据值类型获取{@link JSONValueWriter},首先判断对象是否实现了{@link JSONValueWriter}接口
- * 如果未实现从{@link GlobalValueWriterMapping}中查找全局的writer,否则返回null。 - * - * @param value 值 - * @param 值类型 - * @return {@link JSONValueWriter} - */ - @SuppressWarnings("unchecked") - public static JSONValueWriter getValueWriter(final T value) { - if (value instanceof JSONValueWriter) { - return (JSONValueWriter) value; - } - // 全局自定义序列化,支持null的自定义写出 - return (JSONValueWriter) GlobalValueWriterMapping.get(null == value ? null : value.getClass()); - } - /** * 根据目标类型,获取对应的{@link JSONDeserializer},首先判断是否实现了{@link JSONDeserializer}接口
* 如果未实现从{@link GlobalSerializeMapping}中查找全局的{@link JSONDeserializer},否则返回null diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java index 0af10099b..e46405c75 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java @@ -24,6 +24,7 @@ import org.dromara.hutool.json.serialize.GlobalSerializeMapping; import org.dromara.hutool.json.serialize.JSONArraySerializer; import org.dromara.hutool.json.serialize.JSONDeserializer; import org.dromara.hutool.json.serialize.JSONObjectSerializer; +import org.dromara.hutool.json.writer.GlobalValueWriters; import org.dromara.hutool.json.writer.JSONValueWriter; import org.dromara.hutool.json.writer.JSONWriter; import org.dromara.hutool.json.xml.JSONXMLUtil; @@ -264,10 +265,9 @@ public class JSONUtil { * @return JSON字符串 * @since 5.7.12 */ - @SuppressWarnings({"unchecked", "rawtypes"}) public static String toJsonStr(final Object obj, final JSONConfig jsonConfig) { // 自定义规则,优先级高于全局规则 - final JSONValueWriter valueWriter = InternalJSONUtil.getValueWriter(obj); + final JSONValueWriter valueWriter = GlobalValueWriters.get(obj); if (null != valueWriter) { final StringWriter stringWriter = new StringWriter(); final JSONWriter jsonWriter = JSONWriter.of(stringWriter, 0, 0, null); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java index cde4e257e..c81a52869 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java @@ -13,19 +13,16 @@ package org.dromara.hutool.json.mapper; import org.dromara.hutool.core.array.ArrayUtil; -import org.dromara.hutool.core.math.NumberUtil; -import org.dromara.hutool.core.reflect.ClassUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.util.ObjUtil; -import org.dromara.hutool.json.*; +import org.dromara.hutool.json.JSON; +import org.dromara.hutool.json.JSONArray; +import org.dromara.hutool.json.JSONConfig; +import org.dromara.hutool.json.JSONObject; import org.dromara.hutool.json.serialize.JSONStringer; +import org.dromara.hutool.json.writer.GlobalValueWriters; import java.math.BigDecimal; -import java.sql.SQLException; -import java.time.temporal.TemporalAccessor; -import java.util.Calendar; -import java.util.Date; -import java.util.Map; /** * 对象和JSON值映射器,用于转换对象为JSON对象中的值
@@ -129,7 +126,7 @@ public class JSONValueMapper { // null、JSON、字符串和自定义对象原样存储 if (null == object // 当用户自定义了对象的字符串表示形式,则保留这个对象 - || null != InternalJSONUtil.getValueWriter(object) + || null != GlobalValueWriters.get(object) || object instanceof JSON // || object instanceof JSONStringer // || object instanceof CharSequence // @@ -138,53 +135,12 @@ public class JSONValueMapper { return object; } - // 合法数字原样存储 - if(object instanceof Number){ - if(!NumberUtil.isValidNumber((Number) object)){ - throw new JSONException("JSON does not allow non-finite numbers."); - } - return object; - } - - // 日期类型做包装,以便自定义输出格式 - if (object instanceof Date - || object instanceof Calendar - || object instanceof TemporalAccessor - ) { - // 日期类型保存原始类型,用于在writer时自定义转字符串 - return object; - } - // 特定对象转换 try { - // fix issue#1399@Github - if (object instanceof SQLException - ) { - return object.toString(); - } - // JSONArray if (object instanceof Iterable || ArrayUtil.isArray(object)) { return new JSONArray(object, jsonConfig); } - // JSONObject - if (object instanceof Map || object instanceof Map.Entry) { - return new JSONObject(object, jsonConfig); - } - - // pr#3507 - // Class类型保存类名 - if (object instanceof Class) { - return ((Class) object).getName(); - } - - // 枚举类保存其字符串形式(4.0.2新增) - if (object instanceof Enum - // Java内部类不做转换 - || ClassUtil.isJdkClass(object.getClass()) - ) { - return object.toString(); - } // 默认按照JSONObject对待 return new JSONObject(object, jsonConfig); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/BooleanValueWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/BooleanValueWriter.java index 26e2ef30f..69f05ef09 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/BooleanValueWriter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/BooleanValueWriter.java @@ -18,14 +18,19 @@ package org.dromara.hutool.json.writer; * @author looly * @since 6.0.0 */ -public class BooleanValueWriter implements JSONValueWriter { +public class BooleanValueWriter implements JSONValueWriter { /** * 单例对象 */ public static final BooleanValueWriter INSTANCE = new BooleanValueWriter(); @Override - public void write(final JSONWriter writer, final Boolean bool) { + public boolean test(final Object bool) { + return bool instanceof Boolean; + } + + @Override + public void write(final JSONWriter writer, final Object bool) { writer.writeRaw(bool.toString()); } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/ClassValueWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/ClassValueWriter.java new file mode 100644 index 000000000..c6f6e679b --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/ClassValueWriter.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023-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; + +/** + * {@link Class}类型的值写出器 + * + * @author looly + * @since 6.0.0 + */ +public class ClassValueWriter implements JSONValueWriter { + /** + * 单例对象 + */ + public static final ClassValueWriter INSTANCE = new ClassValueWriter(); + + @Override + public boolean test(final Object value) { + return value instanceof Class; + } + + @Override + public void write(final JSONWriter writer, final Object value) { + writer.writeQuoteStrValue(((Class) value).getName()); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/DateValueWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/DateValueWriter.java index 6aea944e9..223502ff4 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/DateValueWriter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/DateValueWriter.java @@ -25,12 +25,17 @@ import java.util.Date; * @author looly * @since 6.0.0 */ -public class DateValueWriter implements JSONValueWriter { +public class DateValueWriter implements JSONValueWriter { /** * 单例对象 */ public static final DateValueWriter INSTANCE = new DateValueWriter(); + @Override + public boolean test(final Object value) { + return value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor; + } + @Override public void write(final JSONWriter writer, final Object value) { writer.writeRaw(new DateJSONString(value, writer.getConfig()).toJSONString()); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/GlobalValueWriterMapping.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/GlobalValueWriterMapping.java deleted file mode 100644 index b8a909bba..000000000 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/GlobalValueWriterMapping.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 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; - -import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; -import org.dromara.hutool.core.reflect.NullType; -import org.dromara.hutool.core.util.ObjUtil; - -import java.lang.reflect.Type; -import java.util.Map; - -/** - * 全局自定义对象写出
- * 用户通过此全局定义,可针对某些特殊对象 - * - * @author looly - * @since 6.0.0 - */ -public class GlobalValueWriterMapping { - - private static final Map> writerMap; - - static { - writerMap = new SafeConcurrentHashMap<>(); - } - - /** - * 加入自定义的对象值写出规则 - * - * @param type 对象类型 - * @param writer 自定义对象写出实现 - */ - public static void put(final Type type, final JSONValueWriter writer) { - writerMap.put(ObjUtil.defaultIfNull(type, NullType.INSTANCE), writer); - } - - /** - * 获取自定义对象值写出规则 - * - * @param type 对象类型 - * @return 自定义的 {@link JSONValueWriter} - */ - public static JSONValueWriter get(final Type type) { - return writerMap.get(ObjUtil.defaultIfNull(type, NullType.INSTANCE)); - } -} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/GlobalValueWriters.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/GlobalValueWriters.java new file mode 100644 index 000000000..46b6714c3 --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/GlobalValueWriters.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 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; + +import org.dromara.hutool.core.lang.Assert; + +import java.util.*; + +/** + * 全局自定义对象写出
+ * 用户通过此全局定义,可针对某些特殊对象 + * + * @author looly + * @since 6.0.0 + */ +public class GlobalValueWriters { + + private static final List valueWriterList; + + static { + valueWriterList = Collections.synchronizedList(new LinkedList<>()); + valueWriterList.add(NumberValueWriter.INSTANCE); + valueWriterList.add(DateValueWriter.INSTANCE); + valueWriterList.add(BooleanValueWriter.INSTANCE); + valueWriterList.add(JSONStringValueWriter.INSTANCE); + valueWriterList.add(ClassValueWriter.INSTANCE); + valueWriterList.add(JdkValueWriter.INSTANCE); + } + + /** + * 加入自定义的对象值写出规则,自定义规则总是优先 + * + * @param valueWriter 自定义对象写出实现 + */ + public static void add(final JSONValueWriter valueWriter) { + valueWriterList.add(0, Assert.notNull(valueWriter)); + } + + /** + * 获取自定义对象值写出规则 + * + * @param value 值,{@code null}表示需要自定义null的输出 + * @return 自定义的 {@link JSONValueWriter} + */ + public static JSONValueWriter get(final Object value) { + if (value instanceof JSONValueWriter) { + return (JSONValueWriter) value; + } + + return valueWriterList.stream().filter(writer -> writer.test(value)).findFirst().orElse(null); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONStringValueWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONStringValueWriter.java index cdd458bea..94fe56923 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONStringValueWriter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONStringValueWriter.java @@ -15,23 +15,23 @@ package org.dromara.hutool.json.writer; import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.serialize.JSONStringer; -import java.time.temporal.TemporalAccessor; -import java.util.Calendar; -import java.util.Date; - /** - * 日期类型的值写出器
- * 支持包括:{@link Date}、{@link Calendar}、{@link TemporalAccessor} + * {@link JSONStringer}的值写出器 * * @author looly * @since 6.0.0 */ -public class JSONStringValueWriter implements JSONValueWriter { +public class JSONStringValueWriter implements JSONValueWriter { /** * 单例对象 */ public static final JSONStringValueWriter INSTANCE = new JSONStringValueWriter(); + @Override + public boolean test(final Object value) { + return value instanceof JSONStringer; + } + /** * 输出实现了{@link JSONStringer}接口的对象,通过调用{@link JSONStringer#toJSONString()}获取JSON字符串
* {@link JSONStringer}按照JSON对象对待,此方法输出的JSON字符串不包装引号。
@@ -41,10 +41,10 @@ public class JSONStringValueWriter implements JSONValueWriter { * @param jsonStringer {@link JSONStringer} */ @Override - public void write(final JSONWriter writer, final JSONStringer jsonStringer) { + public void write(final JSONWriter writer, final Object jsonStringer) { final String valueStr; try { - valueStr = jsonStringer.toJSONString(); + valueStr = ((JSONStringer)jsonStringer).toJSONString(); } catch (final Exception e) { throw new JSONException(e); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONValueWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONValueWriter.java index cfb92a905..391fa306c 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONValueWriter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONValueWriter.java @@ -12,14 +12,32 @@ package org.dromara.hutool.json.writer; +import java.util.function.Predicate; + /** - * JSON的值自定义写出 + * JSON的值自定义写出,通过自定义实现此接口,实现对象自定义写出字符串形式
+ * 如自定义的一个CustomBean,我只希望输出id的值,此时自定义此接口: + *
{@code
+ *   GlobalValueWriters.add(new JSONValueWriter() {
+ *     @Override
+ *     public boolean test(final Object value) {
+ *       return value instanceof CustomBean;
+ *     }
+ *
+ *     @Override
+ *     public void write(final JSONWriter writer, final Object value) {
+ *       writer.writeRaw(String.valueOf(((CustomBean)value).getId()));
+ *     }
+ *   });
+ * }
+ * + * 其中{@link JSONValueWriter#test(Object)}负责判断何种对象使用此规则,{@link JSONValueWriter#write(JSONWriter, Object)}负责写出规则。
+ * 注意:使用{@link GlobalValueWriters#add(JSONValueWriter)}加入全局转换规则后,在JSON对象中,自定义对象不会被转换,而是原始对象存在。 * - * @param 写出的对象类型 * @author looly * @since 6.0.0 */ -public interface JSONValueWriter { +public interface JSONValueWriter extends Predicate { /** * 使用{@link JSONWriter} 写出对象 @@ -27,5 +45,5 @@ public interface JSONValueWriter { * @param writer {@link JSONWriter} * @param value 被写出的值 */ - void write(JSONWriter writer, T value); + void write(JSONWriter writer, Object value); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONWriter.java index 0b279794f..d20439170 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONWriter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONWriter.java @@ -14,19 +14,15 @@ package org.dromara.hutool.json.writer; import org.dromara.hutool.core.io.IORuntimeException; import org.dromara.hutool.core.lang.mutable.MutableEntry; -import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.CharUtil; +import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.InternalJSONUtil; import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONConfig; -import org.dromara.hutool.json.serialize.JSONStringer; import java.io.IOException; import java.io.Writer; -import java.time.temporal.TemporalAccessor; -import java.util.Calendar; -import java.util.Date; import java.util.function.Predicate; /** @@ -311,30 +307,22 @@ public class JSONWriter extends Writer { * @param predicate 过滤修改器 * @return this */ - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings("resource") private JSONWriter writeObjValue(final Object value, final Predicate> predicate) { final int indent = indentFactor + this.indent; // 自定义规则 - final JSONValueWriter valueWriter = InternalJSONUtil.getValueWriter(value); + final JSONValueWriter valueWriter = GlobalValueWriters.get(value); if(null != valueWriter){ valueWriter.write(this, value); return this; } + // 默认规则 if (value == null) { - //noinspection resource writeRaw(StrUtil.NULL); }else if (value instanceof JSON) { ((JSON) value).write(writer, indentFactor, indent, predicate); - } else if (value instanceof Number) { - NumberValueWriter.INSTANCE.write(this, (Number) value); - } else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) { - DateValueWriter.INSTANCE.write(this, value); - } else if (value instanceof Boolean) { - BooleanValueWriter.INSTANCE.write(this, (Boolean) value); - } else if (value instanceof JSONStringer) { - JSONStringValueWriter.INSTANCE.write(this, (JSONStringer) value); } else { writeQuoteStrValue(value.toString()); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JdkValueWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JdkValueWriter.java new file mode 100644 index 000000000..99b8985ba --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JdkValueWriter.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 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; + +import org.dromara.hutool.core.array.ArrayUtil; +import org.dromara.hutool.core.reflect.ClassUtil; + +import java.sql.SQLException; +import java.util.Map; +import java.util.Optional; + +/** + * JDK内置类型的值写出器 + * + *

+ * 枚举类和JDK内部类直接使用toString输出,不做转换。 + *

+ * + *

+ * {@link SQLException}实现了Iterable导致被识别为列表,可能造成死循环,此处按照字符串处理,见: + * https://github.com/dromara/hutool/issues/1399 + *

+ * + * @author looly + * @since 6.0.0 + */ +public class JdkValueWriter implements JSONValueWriter { + /** + * 单例对象 + */ + public static final JdkValueWriter INSTANCE = new JdkValueWriter(); + + @Override + public boolean test(final Object value) { + if (null == value) { + return false; + } + if (value instanceof Enum || value instanceof SQLException) { + return true; + } + + // 可转换为JSONObject和JSONArray的对象 + if (value instanceof Map + || value instanceof Map.Entry + || value instanceof Iterable + || ArrayUtil.isArray(value) + || value instanceof Optional + ) { + return false; + } + + // Java内部类不做转换 + return ClassUtil.isJdkClass(value.getClass()); + } + + @Override + public void write(final JSONWriter writer, final Object value) { + writer.writeQuoteStrValue(value.toString()); + } +} 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 9fde4cc57..cd04048cb 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 @@ -14,6 +14,7 @@ package org.dromara.hutool.json.writer; import org.dromara.hutool.core.math.NumberUtil; import org.dromara.hutool.json.JSONConfig; +import org.dromara.hutool.json.JSONException; /** * 数字类型的值写出器 @@ -21,7 +22,7 @@ import org.dromara.hutool.json.JSONConfig; * @author looly * @since 6.0.0 */ -public class NumberValueWriter implements JSONValueWriter { +public class NumberValueWriter implements JSONValueWriter { /** * JS中表示的数字最大值 @@ -33,19 +34,32 @@ public class NumberValueWriter implements JSONValueWriter { */ public static final NumberValueWriter INSTANCE = new NumberValueWriter(); + @Override + public boolean test(final Object value) { + // 合法数字原样存储 + if(value instanceof Number){ + if(!NumberUtil.isValidNumber((Number) value)){ + throw new JSONException("JSON does not allow non-finite numbers."); + } + return true; + } + return false; + } + /** * 写出数字,根据{@link JSONConfig#isStripTrailingZeros()} 配置不同,写出不同数字
* 主要针对Double型是否去掉小数点后多余的0
* 此方法输出的值不包装引号。 * * @param writer {@link JSONWriter} - * @param number 数字 + * @param value 数字 */ @Override - public void write(final JSONWriter writer, final Number number) { + public void write(final JSONWriter writer, final Object value) { final JSONConfig config = writer.getConfig(); // since 5.6.2可配置是否去除末尾多余0,例如如果为true,5.0返回5 final boolean isStripTrailingZeros = (null == config) || config.isStripTrailingZeros(); + final Number number = (Number) value; final String numberStr = NumberUtil.toStr(number, isStripTrailingZeros); final NumberWriteMode numberWriteMode = (null == config) ? NumberWriteMode.NORMAL : config.getNumberWriteMode(); 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 index 067eb21d3..2c085f789 100644 --- 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 @@ -25,7 +25,7 @@ public enum NumberWriteMode { */ NORMAL, /** - * 浏览器中Javascript兼容模式,此模式下,如果Long输出长度大于 + * 浏览器中Javascript兼容模式,此模式下,如果Long输出长度大于JS中最大长度,则转为字符串形式 */ JS, /** diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue1399Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue1399Test.java new file mode 100644 index 000000000..cc03eca8f --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue1399Test.java @@ -0,0 +1,18 @@ +package org.dromara.hutool.json; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.sql.SQLException; + +/** + * https://github.com/dromara/hutool/issues/1399
+ * 异常SQLException实现了Iterable导致被识别为列表,可能造成死循环,此处按照字符串处理 + */ +public class Issue1399Test { + @Test + void sqlExceptionTest() { + final JSONObject set = JSONUtil.ofObj().set("error", new SQLException("test")); + Assertions.assertEquals("{\"error\":\"java.sql.SQLException: test\"}", set.toString()); + } +} diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2090Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2090Test.java index e3c97b835..274f153d2 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2090Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2090Test.java @@ -12,7 +12,6 @@ package org.dromara.hutool.json; -import org.dromara.hutool.core.lang.Console; import lombok.Data; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -33,7 +32,6 @@ public class Issue2090Test { test.setLocalDate(LocalDate.now()); final JSONObject json = JSONUtil.parseObj(test); - Console.log(json); final TestBean test1 = json.toBean(TestBean.class); Assertions.assertEquals(test, test1); } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONObjectTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONObjectTest.java index 4e9f2e24f..740560108 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONObjectTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONObjectTest.java @@ -337,8 +337,8 @@ public class JSONObjectTest { bean.setTestEnum(TestEnum.TYPE_B); final JSONObject json = JSONUtil.parseObj(bean, false); - // 枚举转换检查 - Assertions.assertEquals("TYPE_B", json.get("testEnum")); + // 枚举转换检查,更新:枚举原样保存,在writer时调用toString。 + Assertions.assertEquals(TestEnum.TYPE_B, json.get("testEnum")); final TestBean bean2 = json.toBean(TestBean.class); Assertions.assertEquals(bean.toString(), bean2.toString()); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Pr3507Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Pr3507Test.java new file mode 100644 index 000000000..58cb8d835 --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Pr3507Test.java @@ -0,0 +1,12 @@ +package org.dromara.hutool.json; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class Pr3507Test { + @Test + void writeClassTest() { + final JSONObject set = JSONUtil.ofObj().set("name", Pr3507Test.class); + Assertions.assertEquals("{\"name\":\"org.dromara.hutool.json.Pr3507Test\"}", set.toString()); + } +} diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/writer/GlobalValueWriterMappingTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/writer/GlobalValueWritersTest.java similarity index 86% rename from hutool-json/src/test/java/org/dromara/hutool/json/writer/GlobalValueWriterMappingTest.java rename to hutool-json/src/test/java/org/dromara/hutool/json/writer/GlobalValueWritersTest.java index 024236438..db29ea751 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/writer/GlobalValueWriterMappingTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/writer/GlobalValueWritersTest.java @@ -20,12 +20,21 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class GlobalValueWriterMappingTest { +public class GlobalValueWritersTest { @BeforeEach public void init(){ - GlobalValueWriterMapping.put(CustomSubBean.class, - (JSONValueWriter) (writer, value) -> writer.writeRaw(String.valueOf(value.getId()))); + GlobalValueWriters.add(new JSONValueWriter() { + @Override + public void write(final JSONWriter writer, final Object value) { + writer.writeRaw(String.valueOf(((CustomSubBean)value).getId())); + } + + @Override + public boolean test(final Object value) { + return value instanceof CustomSubBean; + } + }); } @Test