From e9a615691c30a5d5e9e505cce8a90c63a26155b3 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 3 Oct 2025 19:57:33 +0800 Subject: [PATCH 1/5] add test --- .../cn/hutool/json/xml/IssueID0HP2Test.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 hutool-json/src/test/java/cn/hutool/json/xml/IssueID0HP2Test.java diff --git a/hutool-json/src/test/java/cn/hutool/json/xml/IssueID0HP2Test.java b/hutool-json/src/test/java/cn/hutool/json/xml/IssueID0HP2Test.java new file mode 100644 index 000000000..7b635601b --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/xml/IssueID0HP2Test.java @@ -0,0 +1,22 @@ +package cn.hutool.json.xml; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONConfig; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class IssueID0HP2Test { + + /** + * JSON转换为XML时使用默认的日期格式,并不能自定义格式,日期格式只用于生成JSON字符串 + */ + @Test + void jsonWithDateToXmlTest() { + final JSONObject json = JSONUtil.createObj(JSONConfig.create().setDateFormat("yyyy/MM/dd")) + .set("date", DateUtil.parse("2025-10-03")); + String xml = JSONUtil.toXmlStr(json); + Assertions.assertEquals("2025-10-03 00:00:00", xml); + } +} From 043722e1da2079d1738823e1266f10b1b54838c9 Mon Sep 17 00:00:00 2001 From: asukavuuyn <1346007099@qq.com> Date: Fri, 10 Oct 2025 00:12:05 +0800 Subject: [PATCH 2/5] =?UTF-8?q?fix:charAt=E8=B6=8A=E7=95=8C=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/text/StrBuilder.java | 2 +- .../test/java/cn/hutool/core/text/StrBuilderTest.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java b/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java index 305da2923..87e299f90 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java @@ -486,7 +486,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable { if(index < 0){ index = this.position + index; } - if ((index < 0) || (index > this.position)) { + if ((index < 0) || (index >= this.position)) { throw new StringIndexOutOfBoundsException(index); } return this.value[index]; diff --git a/hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java b/hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java index 474a71143..52f2d9222 100644 --- a/hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java @@ -131,4 +131,13 @@ public class StrBuilderTest { helloWorld.insert(6, "Beautiful "); Assertions.assertEquals("Hello Beautiful World", helloWorld.toString()); } + + @Test + void charAtTest() { + final StrBuilder helloWorld = StrBuilder.create("Hello World"); + Assertions.assertEquals(helloWorld.charAt(-1),'d'); + Assertions.assertEquals(helloWorld.charAt(0),'H'); + Assertions.assertEquals(helloWorld.charAt(10),'d'); + Assertions.assertThrows(StringIndexOutOfBoundsException.class, () -> helloWorld.charAt(11));; + } } From a45bfebd07410a337cbd3337e1f562862fd84a34 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 10 Oct 2025 17:05:15 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D`Sftp.upload`=E7=9B=AE?= =?UTF-8?q?=E6=A0=87=E8=B7=AF=E5=BE=84=E4=B8=BAnull=E6=97=B6=E7=A9=BA?= =?UTF-8?q?=E6=8C=87=E9=92=88=E9=97=AE=E9=A2=98=EF=BC=88issue#ID14WX@Gitee?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 ++- .../java/cn/hutool/core/util/StrUtilTest.java | 5 +++-- .../src/main/java/cn/hutool/extra/ssh/Sftp.java | 16 ++++++++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5a4d3014..dd50215f6 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.8.41(2025-09-29) +# 5.8.41(2025-10-10) ### 🐣新特性 * 【core 】 增加`WeakKeyValueConcurrentMap`及其关联类,同时废弃`WeakConcurrentMap`并替换(issue#4039@Github) @@ -33,6 +33,7 @@ * 【extra 】 修复`JschSessionPool`并发问题(pr#4079@Github) * 【extra 】 修复`Sftp`递归删除目录时使用相对路径可能导致死循环的问题(pr#1380@Gitee) * 【db 】 修复`SqlUtil.removeOuterOrderBy`处理没有order by的语句导致异常问题(pr#4089@Github) +* 【extra 】 修复`Sftp.upload`目标路径为null时空指针问题(issue#ID14WX@Gitee) ------------------------------------------------------------------------------------------------------------- # 5.8.40(2025-08-26) diff --git a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java index 81435d3e7..e3228d931 100755 --- a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.util; +import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Dict; import org.junit.jupiter.api.Test; @@ -633,14 +634,14 @@ public class StrUtilTest { public void replaceLastTest() { final String str = "i am jackjack"; final String result = StrUtil.replaceLast(str, "JACK", null, true); - assertEquals(result, "i am jack"); + assertEquals("i am jack", result); } @Test public void replaceFirstTest() { final String str = "yesyes i do"; final String result = StrUtil.replaceFirst(str, "YES", "", true); - assertEquals(result, "yes i do"); + assertEquals("yes i do", result); } @Test diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java index 0fa65b9e5..133e294c7 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java @@ -3,6 +3,7 @@ package cn.hutool.extra.ssh; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Filter; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.ftp.AbstractFtp; @@ -538,7 +539,8 @@ public class Sftp extends AbstractFtp { * @since 5.7.16 */ public boolean upload(String destPath, String fileName, InputStream fileStream) { - destPath = StrUtil.addSuffixIfNot(destPath, StrUtil.SLASH) + StrUtil.removePrefix(fileName, StrUtil.SLASH); + Assert.notEmpty(fileName); + destPath = StrUtil.addSuffixIfNot(StrUtil.nullToEmpty(destPath), StrUtil.SLASH) + StrUtil.removePrefix(fileName, StrUtil.SLASH); put(fileStream, destPath, null, Mode.OVERWRITE); return true; } @@ -570,13 +572,16 @@ public class Sftp extends AbstractFtp { * 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。 * * @param srcFilePath 本地文件路径 - * @param destPath 目标路径, + * @param destPath 目标路径,{@code null}表示当前路径 * @param monitor 上传进度监控,通过实现此接口完成进度显示 * @param mode {@link Mode} 模式 * @return this * @since 4.6.5 */ - public Sftp put(String srcFilePath, String destPath, SftpProgressMonitor monitor, Mode mode) { + public Sftp put(String srcFilePath, String destPath, SftpProgressMonitor monitor, Mode mode) { + if(null == destPath){ + destPath = pwd(); + } try { getClient().put(srcFilePath, destPath, monitor, mode.ordinal()); } catch (SftpException e) { @@ -589,13 +594,16 @@ public class Sftp extends AbstractFtp { * 将本地数据流上传到目标服务器,目标文件名为destPath,目标必须为文件 * * @param srcStream 本地的数据流 - * @param destPath 目标路径, + * @param destPath 目标路径,{@code null}表示当前路径 * @param monitor 上传进度监控,通过实现此接口完成进度显示 * @param mode {@link Mode} 模式 * @return this * @since 5.7.16 */ public Sftp put(InputStream srcStream, String destPath, SftpProgressMonitor monitor, Mode mode) { + if(null == destPath){ + destPath = pwd(); + } try { getClient().put(srcStream, destPath, monitor, mode.ordinal()); } catch (SftpException e) { From 69c2916ee067220a0bc7d859d234a7f20e8f0244 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 10 Oct 2025 17:28:43 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D`AIConfigBuilder`?= =?UTF-8?q?=E4=B8=AD=E6=96=B9=E6=B3=95=E5=90=8D=E6=8B=BC=E5=86=99=E9=94=99?= =?UTF-8?q?=E8=AF=AF=EF=BC=88pr#1382@Gitee=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../cn/hutool/ai/core/AIConfigBuilder.java | 34 ++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd50215f6..83ad7dc3f 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ * 【extra 】 修复`Sftp`递归删除目录时使用相对路径可能导致死循环的问题(pr#1380@Gitee) * 【db 】 修复`SqlUtil.removeOuterOrderBy`处理没有order by的语句导致异常问题(pr#4089@Github) * 【extra 】 修复`Sftp.upload`目标路径为null时空指针问题(issue#ID14WX@Gitee) +* 【ai 】 修复`AIConfigBuilder`中方法名拼写错误(pr#1382@Gitee) ------------------------------------------------------------------------------------------------------------- # 5.8.40(2025-08-26) diff --git a/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java b/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java index 4065056ac..bedd79071 100644 --- a/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java +++ b/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java @@ -112,8 +112,21 @@ public class AIConfigBuilder { * @param timeout 超时时间 * @return config * @since 5.8.39 + * @deprecated 请使用 {@link #setTimeout(int)} */ - public synchronized AIConfigBuilder setTimout(final int timeout) { + @Deprecated + public AIConfigBuilder setTimout(final int timeout) { + return setTimeout(timeout); + } + + /** + * 设置连接超时时间,不设置为默认值 + * + * @param timeout 超时时间 + * @return config + * @since 5.8.41 + */ + public synchronized AIConfigBuilder setTimeout(final int timeout) { if (timeout > 0) { config.setTimeout(timeout); } @@ -126,10 +139,23 @@ public class AIConfigBuilder { * @param readTimout 取超时时间 * @return config * @since 5.8.39 + * @deprecated 请使用 {@link #setReadTimeout(int)} */ - public synchronized AIConfigBuilder setReadTimout(final int readTimout) { - if (readTimout > 0) { - config.setReadTimeout(readTimout); + @Deprecated + public AIConfigBuilder setReadTimout(final int readTimout) { + return setReadTimeout(readTimout); + } + + /** + * 设置读取超时时间,不设置为默认值 + * + * @param readTimeout 取超时时间 + * @return config + * @since 5.8.41 + */ + public synchronized AIConfigBuilder setReadTimeout(final int readTimeout) { + if (readTimeout > 0) { + config.setReadTimeout(readTimeout); } return this; } From fafec9d351c2e11e4d47bd83e58abd47f0efe367 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 10 Oct 2025 17:34:10 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D`StrBuilder`charAt?= =?UTF-8?q?=E8=B6=8A=E7=95=8C=E5=88=A4=E6=96=AD=E9=94=99=E8=AF=AF=EF=BC=88?= =?UTF-8?q?pr#4094@Github=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../src/test/java/cn/hutool/core/text/StrBuilderTest.java | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83ad7dc3f..fd6379237 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ * 【db 】 修复`SqlUtil.removeOuterOrderBy`处理没有order by的语句导致异常问题(pr#4089@Github) * 【extra 】 修复`Sftp.upload`目标路径为null时空指针问题(issue#ID14WX@Gitee) * 【ai 】 修复`AIConfigBuilder`中方法名拼写错误(pr#1382@Gitee) +* 【core 】 修复`StrBuilder`charAt越界判断错误(pr#4094@Github) ------------------------------------------------------------------------------------------------------------- # 5.8.40(2025-08-26) diff --git a/hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java b/hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java index 52f2d9222..04a277af4 100644 --- a/hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/StrBuilderTest.java @@ -135,9 +135,9 @@ public class StrBuilderTest { @Test void charAtTest() { final StrBuilder helloWorld = StrBuilder.create("Hello World"); - Assertions.assertEquals(helloWorld.charAt(-1),'d'); - Assertions.assertEquals(helloWorld.charAt(0),'H'); - Assertions.assertEquals(helloWorld.charAt(10),'d'); + Assertions.assertEquals('d', helloWorld.charAt(-1)); + Assertions.assertEquals('H', helloWorld.charAt(0)); + Assertions.assertEquals('d', helloWorld.charAt(10)); Assertions.assertThrows(StringIndexOutOfBoundsException.class, () -> helloWorld.charAt(11));; } }