mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-12-07 01:28:34 +08:00
Merge branch 'chinabugotech:v5-dev' into v5-dev
This commit is contained in:
commit
997524d784
@ -2,7 +2,7 @@
|
|||||||
# 🚀Changelog
|
# 🚀Changelog
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
# 5.8.41(2025-09-29)
|
# 5.8.41(2025-10-10)
|
||||||
|
|
||||||
### 🐣新特性
|
### 🐣新特性
|
||||||
* 【core 】 增加`WeakKeyValueConcurrentMap`及其关联类,同时废弃`WeakConcurrentMap`并替换(issue#4039@Github)
|
* 【core 】 增加`WeakKeyValueConcurrentMap`及其关联类,同时废弃`WeakConcurrentMap`并替换(issue#4039@Github)
|
||||||
@ -33,6 +33,9 @@
|
|||||||
* 【extra 】 修复`JschSessionPool`并发问题(pr#4079@Github)
|
* 【extra 】 修复`JschSessionPool`并发问题(pr#4079@Github)
|
||||||
* 【extra 】 修复`Sftp`递归删除目录时使用相对路径可能导致死循环的问题(pr#1380@Gitee)
|
* 【extra 】 修复`Sftp`递归删除目录时使用相对路径可能导致死循环的问题(pr#1380@Gitee)
|
||||||
* 【db 】 修复`SqlUtil.removeOuterOrderBy`处理没有order by的语句导致异常问题(pr#4089@Github)
|
* 【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)
|
# 5.8.40(2025-08-26)
|
||||||
|
|||||||
@ -112,8 +112,21 @@ public class AIConfigBuilder {
|
|||||||
* @param timeout 超时时间
|
* @param timeout 超时时间
|
||||||
* @return config
|
* @return config
|
||||||
* @since 5.8.39
|
* @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) {
|
if (timeout > 0) {
|
||||||
config.setTimeout(timeout);
|
config.setTimeout(timeout);
|
||||||
}
|
}
|
||||||
@ -126,10 +139,23 @@ public class AIConfigBuilder {
|
|||||||
* @param readTimout 取超时时间
|
* @param readTimout 取超时时间
|
||||||
* @return config
|
* @return config
|
||||||
* @since 5.8.39
|
* @since 5.8.39
|
||||||
|
* @deprecated 请使用 {@link #setReadTimeout(int)}
|
||||||
*/
|
*/
|
||||||
public synchronized AIConfigBuilder setReadTimout(final int readTimout) {
|
@Deprecated
|
||||||
if (readTimout > 0) {
|
public AIConfigBuilder setReadTimout(final int readTimout) {
|
||||||
config.setReadTimeout(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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -486,7 +486,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
|
|||||||
if(index < 0){
|
if(index < 0){
|
||||||
index = this.position + index;
|
index = this.position + index;
|
||||||
}
|
}
|
||||||
if ((index < 0) || (index > this.position)) {
|
if ((index < 0) || (index >= this.position)) {
|
||||||
throw new StringIndexOutOfBoundsException(index);
|
throw new StringIndexOutOfBoundsException(index);
|
||||||
}
|
}
|
||||||
return this.value[index];
|
return this.value[index];
|
||||||
|
|||||||
@ -131,4 +131,13 @@ public class StrBuilderTest {
|
|||||||
helloWorld.insert(6, "Beautiful ");
|
helloWorld.insert(6, "Beautiful ");
|
||||||
Assertions.assertEquals("Hello Beautiful World", helloWorld.toString());
|
Assertions.assertEquals("Hello Beautiful World", helloWorld.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void charAtTest() {
|
||||||
|
final StrBuilder helloWorld = StrBuilder.create("Hello World");
|
||||||
|
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));;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.core.util;
|
package cn.hutool.core.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Console;
|
||||||
import cn.hutool.core.lang.Dict;
|
import cn.hutool.core.lang.Dict;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@ -633,14 +634,14 @@ public class StrUtilTest {
|
|||||||
public void replaceLastTest() {
|
public void replaceLastTest() {
|
||||||
final String str = "i am jackjack";
|
final String str = "i am jackjack";
|
||||||
final String result = StrUtil.replaceLast(str, "JACK", null, true);
|
final String result = StrUtil.replaceLast(str, "JACK", null, true);
|
||||||
assertEquals(result, "i am jack");
|
assertEquals("i am jack", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void replaceFirstTest() {
|
public void replaceFirstTest() {
|
||||||
final String str = "yesyes i do";
|
final String str = "yesyes i do";
|
||||||
final String result = StrUtil.replaceFirst(str, "YES", "", true);
|
final String result = StrUtil.replaceFirst(str, "YES", "", true);
|
||||||
assertEquals(result, "yes i do");
|
assertEquals("yes i do", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package cn.hutool.extra.ssh;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.collection.ListUtil;
|
import cn.hutool.core.collection.ListUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.lang.Filter;
|
import cn.hutool.core.lang.Filter;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.extra.ftp.AbstractFtp;
|
import cn.hutool.extra.ftp.AbstractFtp;
|
||||||
@ -538,7 +539,8 @@ public class Sftp extends AbstractFtp {
|
|||||||
* @since 5.7.16
|
* @since 5.7.16
|
||||||
*/
|
*/
|
||||||
public boolean upload(String destPath, String fileName, InputStream fileStream) {
|
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);
|
put(fileStream, destPath, null, Mode.OVERWRITE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -570,13 +572,16 @@ public class Sftp extends AbstractFtp {
|
|||||||
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。
|
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。
|
||||||
*
|
*
|
||||||
* @param srcFilePath 本地文件路径
|
* @param srcFilePath 本地文件路径
|
||||||
* @param destPath 目标路径,
|
* @param destPath 目标路径,{@code null}表示当前路径
|
||||||
* @param monitor 上传进度监控,通过实现此接口完成进度显示
|
* @param monitor 上传进度监控,通过实现此接口完成进度显示
|
||||||
* @param mode {@link Mode} 模式
|
* @param mode {@link Mode} 模式
|
||||||
* @return this
|
* @return this
|
||||||
* @since 4.6.5
|
* @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 {
|
try {
|
||||||
getClient().put(srcFilePath, destPath, monitor, mode.ordinal());
|
getClient().put(srcFilePath, destPath, monitor, mode.ordinal());
|
||||||
} catch (SftpException e) {
|
} catch (SftpException e) {
|
||||||
@ -589,13 +594,16 @@ public class Sftp extends AbstractFtp {
|
|||||||
* 将本地数据流上传到目标服务器,目标文件名为destPath,目标必须为文件
|
* 将本地数据流上传到目标服务器,目标文件名为destPath,目标必须为文件
|
||||||
*
|
*
|
||||||
* @param srcStream 本地的数据流
|
* @param srcStream 本地的数据流
|
||||||
* @param destPath 目标路径,
|
* @param destPath 目标路径,{@code null}表示当前路径
|
||||||
* @param monitor 上传进度监控,通过实现此接口完成进度显示
|
* @param monitor 上传进度监控,通过实现此接口完成进度显示
|
||||||
* @param mode {@link Mode} 模式
|
* @param mode {@link Mode} 模式
|
||||||
* @return this
|
* @return this
|
||||||
* @since 5.7.16
|
* @since 5.7.16
|
||||||
*/
|
*/
|
||||||
public Sftp put(InputStream srcStream, String destPath, SftpProgressMonitor monitor, Mode mode) {
|
public Sftp put(InputStream srcStream, String destPath, SftpProgressMonitor monitor, Mode mode) {
|
||||||
|
if(null == destPath){
|
||||||
|
destPath = pwd();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
getClient().put(srcStream, destPath, monitor, mode.ordinal());
|
getClient().put(srcStream, destPath, monitor, mode.ordinal());
|
||||||
} catch (SftpException e) {
|
} catch (SftpException e) {
|
||||||
|
|||||||
@ -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("<date>2025-10-03 00:00:00</date>", xml);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user