diff --git a/CHANGELOG.md b/CHANGELOG.md index 106f3d78c..9a879a5d5 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ # 5.8.6.M1 (2022-08-30) +### ❌不兼容特性 +* 【json 】 由于设计缺陷,导致JSONObject#write方法中Filter中key的泛型不得已变动为Object,以解决无法递归的bug(issue#I5OMSC@Gitee) + ### 🐣新特性 * 【core 】 CollUtil新增addIfAbsent方法(pr#750@Gitee) * 【core 】 DateUtil.parseUTC支持只有时分的格式(issue#I5M6DP@Gitee) @@ -29,6 +32,7 @@ * 【core 】 修复UrlBuilder.addPath 方法传入非有效路径字符串时,会出现空指针异常的问题(issue#I5O4ML@Gitee) * 【core 】 修复FilterIter当参数filter为空时存在问题(issue#I5OG7U@Gitee) * 【poi 】 修复Excel读取提示信息错误(issue#I5OSFC@Gitee) +* 【json 】 解决JSONObject#write无法递归的bug(issue#I5OMSC@Gitee) ------------------------------------------------------------------------------------------------------------- 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 809d4c652..4923e90ce 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java @@ -537,7 +537,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * @return JSON字符串 * @since 5.7.15 */ - public String toJSONString(int indentFactor, Filter> filter) { + public String toJSONString(int indentFactor, Filter> filter) { final StringWriter sw = new StringWriter(); synchronized (sw.getBuffer()) { return this.write(sw, indentFactor, 0, filter).toString(); @@ -561,16 +561,10 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * @throws JSONException JSON相关异常 * @since 5.7.15 */ - public Writer write(Writer writer, int indentFactor, int indent, Filter> filter) throws JSONException { - final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config) - .beginArray(); + public Writer write(Writer writer, int indentFactor, int indent, Filter> filter) throws JSONException { + final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config).beginArray(); - CollUtil.forEach(this, (value, index) -> { - final MutablePair pair = new MutablePair<>(index, value); - if (null == filter || filter.accept(pair)) { - jsonWriter.writeValue(pair.getValue()); - } - }); + CollUtil.forEach(this, (value, index) -> jsonWriter.writeField(new MutablePair<>(index, value), filter)); jsonWriter.end(); // 此处不关闭Writer,考虑writer后续还需要填内容 return writer; diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java index 41e8ea726..321da8ea6 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -541,7 +541,7 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @return JSON字符串 * @since 5.7.15 */ - public String toJSONString(int indentFactor, Filter> filter) { + public String toJSONString(int indentFactor, Filter> filter) { final StringWriter sw = new StringWriter(); synchronized (sw.getBuffer()) { return this.write(sw, indentFactor, 0, filter).toString(); @@ -565,20 +565,10 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @throws JSONException JSON相关异常 * @since 5.7.15 */ - public Writer write(Writer writer, int indentFactor, int indent, Filter> filter) throws JSONException { + public Writer write(Writer writer, int indentFactor, int indent, Filter> filter) throws JSONException { final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config) .beginObj(); - this.forEach((key, value) -> { - if (null != filter) { - final MutablePair pair = new MutablePair<>(key, value); - if (filter.accept(pair)) { - // 使用修改后的键值对 - jsonWriter.writeField(pair.getKey(), pair.getValue()); - } - } else { - jsonWriter.writeField(key, value); - } - }); + this.forEach((key, value) -> jsonWriter.writeField(new MutablePair<>(key, value), filter)); jsonWriter.end(); // 此处不关闭Writer,考虑writer后续还需要填内容 return writer; diff --git a/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java b/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java index 0a229b386..7fae1d75c 100755 --- a/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java +++ b/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java @@ -5,6 +5,8 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.TemporalAccessorUtil; import cn.hutool.core.date.format.GlobalCustomFormat; import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.lang.Filter; +import cn.hutool.core.lang.mutable.MutablePair; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.NumberUtil; @@ -152,7 +154,7 @@ public class JSONWriter extends Writer { if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){ return this; } - return writeValueDirect(value); + return writeValueDirect(value, null); } /** @@ -162,12 +164,37 @@ public class JSONWriter extends Writer { * @param value 字段值 * @return this * @since 5.7.6 + * @deprecated 请使用 {@link #writeField(MutablePair, Filter)} */ + @Deprecated public JSONWriter writeField(String key, Object value){ if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){ return this; } - return writeKey(key).writeValueDirect(value); + return writeKey(key).writeValueDirect(value, null); + } + + /** + * 写出字段名及字段值,如果字段值是{@code null}且忽略null值,则不写出任何内容 + * + * @param pair 键值对 + * @param filter 键值对的过滤器,可以编辑键值对 + * @return this + * @since 5.8.6 + */ + public JSONWriter writeField(MutablePair pair, Filter> filter){ + if(JSONUtil.isNull(pair.getValue()) && config.isIgnoreNullValue()){ + return this; + } + + if (null == filter || filter.accept(pair)) { + if(false == arrayMode){ + // JSONArray只写值,JSONObject写键值对 + writeKey(StrUtil.toString(pair.getKey())); + } + return writeValueDirect(pair.getValue(), filter); + } + return this; } @Override @@ -194,9 +221,10 @@ public class JSONWriter extends Writer { * 写出值,自动处理分隔符和缩进,自动判断类型,并根据不同类型写出特定格式的值 * * @param value 值 + * @param filter 键值对过滤器 * @return this */ - private JSONWriter writeValueDirect(Object value) { + private JSONWriter writeValueDirect(Object value, Filter> filter) { if (arrayMode) { if (needSeparator) { writeRaw(CharUtil.COMMA); @@ -207,21 +235,26 @@ public class JSONWriter extends Writer { writeRaw(CharUtil.COLON).writeSpace(1); } needSeparator = true; - return writeObjValue(value); + return writeObjValue(value, filter); } /** * 写出JSON的值,根据值类型不同,输出不同内容 * * @param value 值 + * @param filter 过滤器 * @return this */ - private JSONWriter writeObjValue(Object value) { + private JSONWriter writeObjValue(Object value, Filter> filter) { final int indent = indentFactor + this.indent; if (value == null || value instanceof JSONNull) { writeRaw(JSONNull.NULL.toString()); } else if (value instanceof JSON) { - ((JSON) value).write(writer, indentFactor, indent); + if(value instanceof JSONObject){ + ((JSONObject) value).write(writer, indentFactor, indent, filter); + }else if(value instanceof JSONArray){ + ((JSONArray) value).write(writer, indentFactor, indent, filter); + } } else if (value instanceof Map || value instanceof Map.Entry) { new JSONObject(value).write(writer, indentFactor, indent); } else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) { diff --git a/hutool-json/src/test/java/cn/hutool/json/IssueI5OMSCTest.java b/hutool-json/src/test/java/cn/hutool/json/IssueI5OMSCTest.java new file mode 100755 index 000000000..3679e1d5b --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/IssueI5OMSCTest.java @@ -0,0 +1,26 @@ +package cn.hutool.json; + +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.io.resource.ResourceUtil; +import org.junit.Assert; +import org.junit.Test; + +/** + * Predicate多层过滤 + */ +public class IssueI5OMSCTest { + + @Test + public void filterTest(){ + final JSONObject json = JSONUtil.parseObj(ResourceUtil.readUtf8Str("issueI5OMSC.json")); + + final String s = json.toJSONString(0, (entry) -> { + final Object key = entry.getKey(); + if(key instanceof String){ + return ListUtil.of("store", "bicycle", "color", "book", "author").contains(key); + } + return true; + }); + Assert.assertEquals("{\"store\":{\"bicycle\":{\"color\":\"red\"},\"book\":[{\"author\":\"Evelyn Waugh\"},{\"author\":\"Evelyn Waugh02\"}]}}", s); + } +} diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java index 10aa84e14..45ebaa5dd 100755 --- a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java @@ -698,7 +698,7 @@ public class JSONObjectTest { .set("d", true); final String s = json1.toJSONString(0, (pair) -> { - pair.setKey(StrUtil.toUnderlineCase(pair.getKey())); + pair.setKey(StrUtil.toUnderlineCase(pair.getKey().toString())); return true; }); Assert.assertEquals("{\"a_key\":\"value1\",\"b_job\":\"value2\",\"c_good\":\"value3\",\"d\":true}", s); diff --git a/hutool-json/src/test/resources/issueI5OMSC.json b/hutool-json/src/test/resources/issueI5OMSC.json new file mode 100755 index 000000000..2cccb2ccb --- /dev/null +++ b/hutool-json/src/test/resources/issueI5OMSC.json @@ -0,0 +1,32 @@ +{ + "store": { + "bicycle": { + "color": "red", + "price": 19.95 + }, + "book": [ + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99, + "items": [ + { + "name": "wujing001", + "age": 18 + }, + { + "name": "wujing002", + "age": 18 + } + ] + }, + { + "category": "fiction02", + "author": "Evelyn Waugh02", + "title": "Sword of Honour02", + "price": 12.99 + } + ] + } +}