Compare commits

...

44 Commits

Author SHA1 Message Date
Looly
c10c144f64 增加GoldenDB识别(pr#3886@Github) 2025-03-07 10:41:04 +08:00
Golden Looly
0b072015da
Merge pull request #3886 from zchazc/v5-dev
feat: 添加中兴数据库GoldenDB的url识别jdbc-driver逻辑
2025-03-07 10:39:23 +08:00
Looly
8d34a4d26e 修复HttpUtil.normalizeParams规则问题(issue#IBQIYQ@Gitee) 2025-03-07 09:26:44 +08:00
zchazc
c94e3baa28
feat: 添加中兴数据库GoldenDB的url识别jdbc-driver逻辑 2025-03-05 16:50:23 +08:00
Looly
2046809264 修复JsonUtil.toBean泛型数组类型丢失问题(pr#3876@Github) 2025-03-03 12:05:26 +08:00
Looly
1c3e8634c8 add version 2025-03-03 11:41:40 +08:00
Looly
150f8930d0 修复JsonUtil.toBean泛型数组类型丢失问题(pr#3876@Github) 2025-03-03 11:26:21 +08:00
Golden Looly
5b34544b8f
Merge pull request #3876 from winlans/v5-dev
JsonUtil.toBean泛型数组类型丢失修复以及新增VersionUtil版本比较工具
2025-03-03 11:22:09 +08:00
Looly
2c810d92bf HttpBase增加重载可选是否返回声调(pr#3883@Github) 2025-03-03 11:09:10 +08:00
Looly
b2c0d74dd7 Merge branch 'v5-dev' of github.com:dromara/hutool into v5-dev 2025-03-03 10:59:30 +08:00
Golden Looly
fcf78229c4
Merge pull request #3883 from zsdddz/v5-dev
feat(hutool-http): 控制请求头是否聚合
2025-03-03 10:58:45 +08:00
Looly
a74b2f8b0f 修复ReentrantCache#getOrRemoveExpired方法丢失onRemove触发问题(pr#1315@Gitee) 2025-03-03 10:48:05 +08:00
Looly
c41612d21d
!1315 fix: 已过期key,onRemove偶尔触发
Merge pull request !1315 from winlans/v5-dev
2025-03-03 02:46:22 +00:00
zsdddz
b9425a3b2b feat(hutool-http): 控制请求头是否聚合 2025-03-01 16:37:53 +08:00
winlans
bb810d2d64 fix: 已过期key,onRemove偶尔触发 2025-02-28 12:03:40 +08:00
winlans
4c6c3b057a [feature] VersionUtil版本比较工具类 2025-02-27 18:07:07 +08:00
elichow
520b128f1c
Merge pull request #3875 from elichow/v5-dev
V5 dev
2025-02-27 11:47:09 +08:00
winlans
732bea6d0b [bug修复] JsonUtil.toBean泛型数组类型丢失 2025-02-27 11:45:51 +08:00
choweli
10f02bb9bc PinyinUtil增加选择是否返回声调 2025-02-27 10:27:46 +08:00
choweli
f697141cab PinyinUtil增加选择是否返回声调 2025-02-27 10:18:48 +08:00
Looly
bd94c09e91 IdcardUtil验证10位身份证兼容中英文括号(issue#IBP6T1@Gitee) 2025-02-27 08:34:33 +08:00
Looly
1aec0973f8 Merge branch 'v5-dev' of github.com:dromara/hutool into v5-dev 2025-02-26 17:04:59 +08:00
Golden Looly
cb0abbbbd5
Merge pull request #3874 from chinabugotech/revert-3872-v5-dev
Revert "PinyinUtil增加选择是否返回声调"
2025-02-26 16:50:53 +08:00
Golden Looly
dc038f2356
Revert "PinyinUtil增加选择是否返回声调" 2025-02-26 16:50:03 +08:00
chinabugotech
22314d80f9
Merge pull request #3872 from elichow/v5-dev
PinyinUtil增加选择是否返回声调
2025-02-26 15:45:15 +08:00
choweli
220148d555 PinyinUtil增加选择是否返回声调 2025-02-26 13:39:16 +08:00
Looly
1c0b6c3da1 修复SettingLoaderload未抛出异常导致配置文件无法正常遍历的问题(pr#3868@Github) 2025-02-24 10:24:59 +08:00
Looly
4ef8814c14 fix test 2025-02-21 17:52:32 +08:00
Looly
05f16f051e change link 2025-02-21 17:40:14 +08:00
Looly
bfad067365 fix readme 2025-02-21 15:37:12 +08:00
Looly
72277a1a6a Merge branch 'v5-dev' of github.com:dromara/hutool into v5-dev 2025-02-21 15:36:23 +08:00
chinabugotech
63d5a6ead6
update README-EN.md.
Signed-off-by: chinabugotech <bugo@bugotech.cn>
2025-02-20 10:32:42 +00:00
chinabugotech
41e52de401
update README.md.
Signed-off-by: chinabugotech <bugo@bugotech.cn>
2025-02-20 10:29:38 +00:00
chinabugotech
df4683378f
Update README.md 2025-02-20 17:46:35 +08:00
chinabugotech
0154e72eaa
Update README.md 2025-02-20 17:46:13 +08:00
chinabugotech
455a555f43
Update README.md 2025-02-20 17:45:31 +08:00
chinabugotech
cc5b8a290c
update: 更新文件 README.md 2025-02-20 17:17:58 +08:00
Looly
6e83e67a4a FileWriter增加方法,可选是否追加换行符(issue#3858@Github) 2025-02-18 19:01:56 +08:00
Looly
f3c97bdc4d FileWriter增加方法,可选是否追加换行符(issue#3858@Github) 2025-02-18 18:34:14 +08:00
Looly
7608e08c2e FileWriter增加方法,可选是否追加换行符(issue#3858@Github) 2025-02-18 18:03:06 +08:00
Looly
35f0e368d2 ObjectMapper删除重复trim(pr#3859@Github) 2025-02-18 17:39:31 +08:00
Golden Looly
05e68b9683
Merge pull request #3859 from ghjdegithub/patch-1
[bug修复] Update ObjectMapper.java 删除重复调用StrUtil.trim(source)代码
2025-02-18 17:38:04 +08:00
骨灰级
b0e1302332
Update ObjectMapper.java
cn.hutool.json.ObjectMapper.java 212行 mapFromStr函数
重复调用StrUtil.trim(source)
2025-02-18 15:53:36 +08:00
Looly
e6efa72cee prepare 5.8.37 2025-02-18 09:37:19 +08:00
165 changed files with 1097 additions and 348 deletions

2
.github/FUNDING.yml vendored
View File

@ -1,4 +1,4 @@
# These are supported funding model platforms # These are supported funding model platforms
github: [looly] github: [looly]
custom: ['https://gitee.com/dromara/hutool', 'https://dromara.gitee.io/donate.html'] custom: ['https://gitee.com/chinabugotech/hutool']

View File

@ -1,6 +1,24 @@
# 🚀Changelog # 🚀Changelog
-------------------------------------------------------------------------------------------------------------
# 5.8.37(2025-03-07)
### 🐣新特性
* 【json 】 ObjectMapper删除重复trimpr#3859@Github
* 【core 】 `FileWriter`增加方法可选是否追加换行符issue#3858@Github
* 【core 】 `IdcardUtil`验证10位身份证兼容中英文括号issue#IBP6T1@Gitee
* 【extra 】 `PinyinUtil`增加重载可选是否返回声调pr#3875@Github
* 【http 】 `HttpBase`增加重载可选是否返回声调pr#3883@Github
* 【core 】 增加`VersionUtil`版本比较工具pr#3876@Github
* 【db 】 增加GoldenDB识别pr#3886@Github
### 🐞Bug修复
* 【setting】 修复`SettingLoader`load未抛出异常导致配置文件无法正常遍历的问题pr#3868@Github
* 【cache 】 修复`ReentrantCache#getOrRemoveExpired`方法丢失onRemove触发问题pr#1315@Gitee
* 【json 】 修复`JsonUtil.toBean`泛型数组类型丢失问题pr#3876@Github
* 【http 】 修复`HttpUtil.normalizeParams`规则问题issue#IBQIYQ@Gitee
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.8.36(2025-02-18) # 5.8.36(2025-02-18)
@ -1081,4 +1099,4 @@
* 【core 】 修复农历转公历在闰月时错误issue#I4ZSGJ@Gitee * 【core 】 修复农历转公历在闰月时错误issue#I4ZSGJ@Gitee
# 5.7.x 或更早版本 # 5.7.x 或更早版本
* [https://gitee.com/dromara/hutool/blob/v5-master/CHANGELOG_5.0-5.7.md](https://gitee.com/dromara/hutool/blob/v5-master/CHANGELOG_5.0-5.7.md) * [https://gitee.com/chinabugotech/hutool/blob/v5-master/CHANGELOG_5.0-5.7.md](https://gitee.com/chinabugotech/hutool/blob/v5-master/CHANGELOG_5.0-5.7.md)

View File

@ -18,26 +18,26 @@
<a target="_blank" href="https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html"> <a target="_blank" href="https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html">
<img src="https://img.shields.io/badge/JDK-8+-green.svg" /> <img src="https://img.shields.io/badge/JDK-8+-green.svg" />
</a> </a>
<a target="_blank" href="https://travis-ci.com/dromara/hutool"> <a target="_blank" href="https://travis-ci.com/chinabugotech/hutool">
<img src="https://travis-ci.com/dromara/hutool.svg?branch=v5-master" /> <img src="https://travis-ci.com/chinabugotech/hutool.svg?branch=v5-master" />
</a> </a>
<a href="https://www.codacy.com/gh/dromara/hutool/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=dromara/hutool&amp;utm_campaign=Badge_Grade"> <a href="https://www.codacy.com/gh/chinabugotech/hutool/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=chinabugotech/hutool&amp;utm_campaign=Badge_Grade">
<img src="https://app.codacy.com/project/badge/Grade/8a6897d9de7440dd9de8804c28d2871d"/> <img src="https://app.codacy.com/project/badge/Grade/8a6897d9de7440dd9de8804c28d2871d"/>
</a> </a>
<a href="https://codecov.io/gh/dromara/hutool"> <a href="https://codecov.io/gh/chinabugotech/hutool">
<img src="https://codecov.io/gh/dromara/hutool/branch/v5-master/graph/badge.svg" /> <img src="https://codecov.io/gh/chinabugotech/hutool/branch/v5-master/graph/badge.svg" />
</a> </a>
<a target="_blank" href="https://gitter.im/hutool/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"> <a target="_blank" href="https://gitter.im/hutool/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge">
<img src="https://badges.gitter.im/hutool/Lobby.svg" /> <img src="https://badges.gitter.im/hutool/Lobby.svg" />
</a> </a>
<a target="_blank" href='https://gitee.com/dromara/hutool/stargazers'> <a target="_blank" href='https://gitee.com/chinabugotech/hutool/stargazers'>
<img src='https://gitee.com/dromara/hutool/badge/star.svg?theme=gvp' alt='star'/> <img src='https://gitee.com/chinabugotech/hutool/badge/star.svg?theme=gvp' alt='star'/>
</a> </a>
<a target="_blank" href='https://github.com/dromara/hutool'> <a target="_blank" href='https://github.com/chinabugotech/hutool'>
<img src="https://img.shields.io/github/stars/dromara/hutool.svg?style=social" alt="github star"/> <img src="https://img.shields.io/github/stars/chinabugotech/hutool.svg?style=social" alt="github star"/>
</a> </a>
<a target="_blank" href='https://gitcode.com/dromara/hutool'> <a target="_blank" href='https://gitcode.com/chinabugotech/hutool'>
<img src="https://gitcode.com/dromara/hutool/star/badge.svg" alt="gitcode star"/> <img src="https://gitcode.com/chinabugotech/hutool/star/badge.svg" alt="gitcode star"/>
</a> </a>
</p> </p>
@ -49,11 +49,7 @@
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
<p align="center">
<a href="#"><img style="width: 45%" alt="" src="https://plus.hutool.cn/images/zanzhu.jpg"/></a>
</p>
-------------------------------------------------------------------------------
[**🌎中文说明**](README.md) [**🌎中文说明**](README.md)
@ -128,23 +124,7 @@ Each module can be introduced individually, or all modules can be introduced by
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
## 🪙Support Hutool
### 💳Donate
If you think Hutool is good, you can donate to buy the author a pack of chili~, thanks in advance ^_^.
[Gitee donate](https://gitee.com/dromara/hutool)
[Dromara donate](https://dromara.gitee.io/donate.html)
### 👕Shop about Hutool
We provide the T-Shirt and Sweater with Hutool Logo, please visit the shop
👉 [Hutool Shop](https://market.m.taobao.com/apps/market/content/index.html?wh_weex=true&contentId=331724720170) 👈
-------------------------------------------------------------------------------
## 📦Install ## 📦Install
@ -153,18 +133,18 @@ We provide the T-Shirt and Sweater with Hutool Logo, please visit the shop
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.8.36</version> <version>5.8.37</version>
</dependency> </dependency>
``` ```
### 🍐Gradle ### 🍐Gradle
``` ```
implementation 'cn.hutool:hutool-all:5.8.36' implementation 'cn.hutool:hutool-all:5.8.37'
``` ```
## 📥Download ## 📥Download
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.36/) - [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.37/)
> 🔔note: > 🔔note:
> Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available. > Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.
@ -174,9 +154,9 @@ implementation 'cn.hutool:hutool-all:5.8.36'
Download the entire project source code Download the entire project source code
gitee[https://gitee.com/dromara/hutool](https://gitee.com/dromara/hutool) gitee[https://gitee.com/chinabugotech/hutool](https://gitee.com/chinabugotech/hutool)
github:[https://github.com/dromara/hutool](https://github.com/dromara/hutool) github:[https://github.com/chinabugotech/hutool](https://github.com/chinabugotech/hutool)
```sh ```sh
cd ${hutool} cd ${hutool}
@ -200,9 +180,9 @@ Hutool's source code is divided into two branches:
When submitting feedback, please indicate which JDK version, Hutool version, and related dependency library version you are using. When submitting feedback, please indicate which JDK version, Hutool version, and related dependency library version you are using.
- [Gitee issue](https://gitee.com/dromara/hutool/issues) - [Gitee issue](https://gitee.com/chinabugotech/hutool/issues)
- [Github issue](https://github.com/dromara/hutool/issues) - [Github issue](https://github.com/chinabugotech/hutool/issues)
- [Gitcode issue](https://gitcode.com/dromara/hutool/issues) - [Gitcode issue](https://gitcode.com/chinabugotech/hutool/issues)
### 🧬Principles of PR(pull request) ### 🧬Principles of PR(pull request)
@ -221,4 +201,4 @@ Hutool welcomes anyone to contribute code to Hutool, but the author suffers from
## ⭐Star Hutool ## ⭐Star Hutool
[![Stargazers over time](https://starchart.cc/dromara/hutool.svg)](https://starchart.cc/dromara/hutool) [![Stargazers over time](https://starchart.cc/chinabugotech/hutool.svg)](https://starchart.cc/chinabugotech/hutool)

View File

@ -18,26 +18,23 @@
<a target="_blank" href="https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html"> <a target="_blank" href="https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html">
<img src="https://img.shields.io/badge/JDK-8+-green.svg" /> <img src="https://img.shields.io/badge/JDK-8+-green.svg" />
</a> </a>
<a target="_blank" href="https://travis-ci.com/dromara/hutool"> <a target="_blank" href="https://travis-ci.com/chinabugotech/hutool">
<img src="https://travis-ci.com/dromara/hutool.svg?branch=v5-master" /> <img src="https://travis-ci.com/chinabugotech/hutool.svg?branch=v5-master" />
</a> </a>
<a href="https://www.codacy.com/gh/dromara/hutool/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=dromara/hutool&amp;utm_campaign=Badge_Grade"> <a href="https://www.codacy.com/gh/chinabugotech/hutool/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=chinabugotech/hutool&amp;utm_campaign=Badge_Grade">
<img src="https://app.codacy.com/project/badge/Grade/8a6897d9de7440dd9de8804c28d2871d"/> <img src="https://app.codacy.com/project/badge/Grade/8a6897d9de7440dd9de8804c28d2871d"/>
</a> </a>
<a href="https://codecov.io/gh/dromara/hutool"> <a href="https://codecov.io/gh/chinabugotech/hutool">
<img src="https://codecov.io/gh/dromara/hutool/branch/v5-master/graph/badge.svg" /> <img src="https://codecov.io/gh/chinabugotech/hutool/branch/v5-master/graph/badge.svg" />
</a> </a>
<a target="_blank" href="https://gitter.im/hutool/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"> <a target="_blank" href='https://gitee.com/chinabugotech/hutool/stargazers'>
<img src="https://badges.gitter.im/hutool/Lobby.svg" /> <img src='https://gitee.com/chinabugotech/hutool/badge/star.svg?theme=gvp' alt='star'/>
</a> </a>
<a target="_blank" href='https://gitee.com/dromara/hutool/stargazers'> <a target="_blank" href='https://github.com/chinabugotech/hutool'>
<img src='https://gitee.com/dromara/hutool/badge/star.svg?theme=gvp' alt='star'/> <img src="https://img.shields.io/github/stars/chinabugotech/hutool.svg?style=social" alt="github star"/>
</a> </a>
<a target="_blank" href='https://github.com/dromara/hutool'> <a target="_blank" href='https://gitcode.com/chinabugotech/hutool'>
<img src="https://img.shields.io/github/stars/dromara/hutool.svg?style=social" alt="github star"/> <img src="https://gitcode.com/chinabugotech/hutool/star/badge.svg" alt="gitcode star"/>
</a>
<a target="_blank" href='https://gitcode.com/dromara/hutool'>
<img src="https://gitcode.com/dromara/hutool/star/badge.svg" alt="gitcode star"/>
</a> </a>
</p> </p>
@ -49,11 +46,7 @@
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
<p align="center"> =======
<a href="#"><img style="width: 45%" alt="" src="https://plus.hutool.cn/images/zanzhu.jpg"/></a>
</p>
-------------------------------------------------------------------------------
[**🌎English Documentation**](README-EN.md) [**🌎English Documentation**](README-EN.md)
@ -119,23 +112,7 @@ Hutool = Hu + tool是原公司项目底层代码剥离后的开源库“Hu
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
## 🪙支持Hutool
### 💳捐赠
如果你觉得Hutool不错可以捐赠请维护者吃包辣条~,在此表示感谢^_^。
[Gitee上捐赠](https://gitee.com/dromara/hutool)
### 👕周边商店
你也可以通过购买Hutool的周边商品来支持Hutool维护哦
我们提供了印有Hutool Logo的周边商品欢迎点击购买支持
👉 [Hutool 周边商店](https://market.m.taobao.com/apps/market/content/index.html?wh_weex=true&contentId=331724720170) 👈
-------------------------------------------------------------------------------
## 📦安装 ## 📦安装
@ -146,20 +123,20 @@ Hutool = Hu + tool是原公司项目底层代码剥离后的开源库“Hu
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.8.36</version> <version>5.8.37</version>
</dependency> </dependency>
``` ```
### 🍐Gradle ### 🍐Gradle
``` ```
implementation 'cn.hutool:hutool-all:5.8.36' implementation 'cn.hutool:hutool-all:5.8.37'
``` ```
### 📥下载jar ### 📥下载jar
点击以下链接,下载`hutool-all-X.X.X.jar`即可: 点击以下链接,下载`hutool-all-X.X.X.jar`即可:
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.36/) - [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.37/)
> 🔔️注意 > 🔔️注意
> Hutool 5.x支持JDK8+对Android平台没有测试不能保证所有工具类或工具方法可用。 > Hutool 5.x支持JDK8+对Android平台没有测试不能保证所有工具类或工具方法可用。
@ -167,7 +144,7 @@ implementation 'cn.hutool:hutool-all:5.8.36'
### 🚽编译安装 ### 🚽编译安装
访问Hutool的Gitee主页[https://gitee.com/dromara/hutool](https://gitee.com/dromara/hutool) 下载整个项目源码v5-master或v5-dev分支都可然后进入Hutool项目目录执行 访问Hutool的Gitee主页[https://gitee.com/chinabugotech/hutool](https://gitee.com/chinabugotech/hutool) 下载整个项目源码v5-master或v5-dev分支都可然后进入Hutool项目目录执行
```sh ```sh
./hutool.sh install ./hutool.sh install
@ -192,9 +169,9 @@ Hutool的源码分为两个分支功能如下
提交问题反馈请说明正在使用的JDK版本呢、Hutool版本和相关依赖库版本。 提交问题反馈请说明正在使用的JDK版本呢、Hutool版本和相关依赖库版本。
- [Gitee issue](https://gitee.com/dromara/hutool/issues) - [Gitee issue](https://gitee.com/chinabugotech/hutool/issues)
- [Github issue](https://github.com/dromara/hutool/issues) - [Github issue](https://github.com/chinabugotech/hutool/issues)
- [Gitcode issue](https://gitcode.com/dromara/hutool/issues) - [Gitcode issue](https://gitcode.com/chinabugotech/hutool/issues)
### 🧬贡献代码的步骤 ### 🧬贡献代码的步骤
@ -224,4 +201,4 @@ Hutool欢迎任何人为Hutool添砖加瓦贡献代码不过维护者是
## ⭐Star Hutool ## ⭐Star Hutool
[![Stargazers over time](https://starchart.cc/dromara/hutool.svg)](https://starchart.cc/dromara/hutool) [![Stargazers over time](https://starchart.cc/chinabugotech/hutool.svg)](https://starchart.cc/chinabugotech/hutool)

View File

@ -10,6 +10,6 @@
## Reporting a Vulnerability报告漏洞 ## Reporting a Vulnerability报告漏洞
如果你发现有安全问题或漏洞,请发送邮件到`loolly@aliyun.com`。 如果你发现有安全问题或漏洞,请发送邮件到`bugo@bugotech.cn`。
To report any found security issues or vulnerabilities, please send a mail to `loolly@aliyun.com`. To report any found security issues or vulnerabilities, please send a mail to `bugo@bugotech.cn`.

View File

@ -1 +1 @@
5.8.36 5.8.37

View File

@ -1 +1 @@
var version = '5.8.36' var version = '5.8.37'

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-aop</artifactId> <artifactId>hutool-aop</artifactId>

View File

@ -29,7 +29,7 @@ public class CglibProxyFactory extends ProxyFactory{
/** /**
* 创建代理对象<br> * 创建代理对象<br>
* https://gitee.com/dromara/hutool/issues/I74EX7<br> * https://gitee.com/chinabugotech/hutool/issues/I74EX7<br>
* 某些对象存在非空参数构造则需遍历查找需要的构造完成代理对象构建 * 某些对象存在非空参数构造则需遍历查找需要的构造完成代理对象构建
* *
* @param <T> 代理对象类型 * @param <T> 代理对象类型

View File

@ -29,7 +29,7 @@ public class SpringCglibProxyFactory extends ProxyFactory{
/** /**
* 创建代理对象<br> * 创建代理对象<br>
* https://gitee.com/dromara/hutool/issues/I74EX7<br> * https://gitee.com/chinabugotech/hutool/issues/I74EX7<br>
* 某些对象存在非空参数构造则需遍历查找需要的构造完成代理对象构建 * 某些对象存在非空参数构造则需遍历查找需要的构造完成代理对象构建
* *
* @param <T> 代理对象类型 * @param <T> 代理对象类型

View File

@ -30,7 +30,7 @@ public class IssueI74EX7Test {
} }
/** /**
* https://gitee.com/dromara/hutool/issues/I74EX7<br> * https://gitee.com/chinabugotech/hutool/issues/I74EX7<br>
* Enhancer.create()默认调用无参构造有参构造或者多个构造没有很好的兼容 * Enhancer.create()默认调用无参构造有参构造或者多个构造没有很好的兼容
* *
*/ */
@ -42,7 +42,7 @@ public class IssueI74EX7Test {
} }
/** /**
* https://gitee.com/dromara/hutool/issues/I74EX7<br> * https://gitee.com/chinabugotech/hutool/issues/I74EX7<br>
* Enhancer.create()默认调用无参构造有参构造或者多个构造没有很好的兼容 * Enhancer.create()默认调用无参构造有参构造或者多个构造没有很好的兼容
* *
*/ */

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-bloomFilter</artifactId> <artifactId>hutool-bloomFilter</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-bom</artifactId> <artifactId>hutool-bom</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-cache</artifactId> <artifactId>hutool-cache</artifactId>

View File

@ -112,6 +112,7 @@ public abstract class ReentrantCache<K, V> extends AbstractCache<K, V> {
if(null != co && co.isExpired()){ if(null != co && co.isExpired()){
//过期移除 //过期移除
removeWithoutLock(key); removeWithoutLock(key);
onRemove(co.key, co.obj);
co = null; co = null;
} }
} finally { } finally {

View File

@ -4,13 +4,17 @@ import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUnit;
import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* 缓存测试用例 * 缓存测试用例
* @author Looly
* *
* @author Looly
*/ */
public class CacheTest { public class CacheTest {
@ -121,4 +125,27 @@ public class CacheTest {
//取消定时清理 //取消定时清理
timedCache.cancelPruneSchedule(); timedCache.cancelPruneSchedule();
} }
/**
* TimedCache的数据过期后不是每次都触发监听器onRemove而是偶尔触发onRemove
* https://gitee.com/chinabugotech/hutool/issues/IBP752
*/
@Test
public void whenContainsKeyTimeout_shouldCallOnRemove() {
int timeout = 50;
final TimedCache<Integer, String> ALARM_CACHE = new TimedCache<>(timeout);
AtomicInteger counter = new AtomicInteger(0);
ALARM_CACHE.setListener((key, value) -> {
counter.incrementAndGet();
});
ALARM_CACHE.put(1, "value1");
ThreadUtil.sleep(100);
assertFalse(ALARM_CACHE.containsKey(1));
assertEquals(1, counter.get());
}
} }

View File

@ -4,15 +4,16 @@ import cn.hutool.cache.impl.LRUCache;
import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* https://github.com/dromara/hutool/issues/1895<br> * https://github.com/chinabugotech/hutool/issues/1895<br>
* 并发问题测试在5.7.15前LRUCache存在并发问题多线程get后map结构变更导致null的位置不确定 * 并发问题测试在5.7.15前LRUCache存在并发问题多线程get后map结构变更导致null的位置不确定
* 并可能引起死锁 * 并可能引起死锁
*/ */
@ -21,7 +22,7 @@ public class LRUCacheTest {
@Test @Test
@Disabled @Disabled
public void putTest(){ public void putTest(){
//https://github.com/dromara/hutool/issues/2227 //https://github.com/chinabugotech/hutool/issues/2227
final LRUCache<String, String> cache = CacheUtil.newLRUCache(100, 10); final LRUCache<String, String> cache = CacheUtil.newLRUCache(100, 10);
for (int i = 0; i < 10000; i++) { for (int i = 0; i < 10000; i++) {
//ThreadUtil.execute(()-> cache.put(RandomUtil.randomString(5), "1243", 10)); //ThreadUtil.execute(()-> cache.put(RandomUtil.randomString(5), "1243", 10));

View File

@ -2,10 +2,11 @@ package cn.hutool.cache;
import cn.hutool.cache.impl.WeakCache; import cn.hutool.cache.impl.WeakCache;
import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Console;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class WeakCacheTest { public class WeakCacheTest {
@Test @Test
@ -25,7 +26,7 @@ public class WeakCacheTest {
@Test @Test
@Disabled @Disabled
public void removeByGcTest(){ public void removeByGcTest(){
// https://gitee.com/dromara/hutool/issues/I51O7M // https://gitee.com/chinabugotech/hutool/issues/I51O7M
WeakCache<String, String> cache = new WeakCache<>(-1); WeakCache<String, String> cache = new WeakCache<>(-1);
cache.put("a", "1"); cache.put("a", "1");
cache.put("b", "2"); cache.put("b", "2");

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-captcha</artifactId> <artifactId>hutool-captcha</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-core</artifactId> <artifactId>hutool-core</artifactId>

View File

@ -2199,7 +2199,7 @@ public class CollUtil {
iter = (Iterator) value; iter = (Iterator) value;
} else if (value instanceof Iterable) { } else if (value instanceof Iterable) {
if(value instanceof Map && BeanUtil.isBean(TypeUtil.getClass(elementType))){ if(value instanceof Map && BeanUtil.isBean(TypeUtil.getClass(elementType))){
//https://github.com/dromara/hutool/issues/3139 //https://github.com/chinabugotech/hutool/issues/3139
// 如果值为Map而目标为一个Bean则Map应整体转换为Bean而非拆分成Entry转换 // 如果值为Map而目标为一个Bean则Map应整体转换为Bean而非拆分成Entry转换
iter = new ArrayIter<>(new Object[]{value}); iter = new ArrayIter<>(new Object[]{value});
}else{ }else{

View File

@ -36,7 +36,7 @@ public class NumberWithFormat extends Number implements TypeConverter {
// 自定义日期格式 // 自定义日期格式
if (null != this.format && targetType instanceof Class) { if (null != this.format && targetType instanceof Class) {
final Class<?> clazz = (Class<?>) targetType; final Class<?> clazz = (Class<?>) targetType;
// https://gitee.com/dromara/hutool/issues/I6IS5B // https://gitee.com/chinabugotech/hutool/issues/I6IS5B
if (Date.class.isAssignableFrom(clazz)) { if (Date.class.isAssignableFrom(clazz)) {
return new DateConverter((Class<? extends Date>) clazz, format).convert(this.number, null); return new DateConverter((Class<? extends Date>) clazz, format).convert(this.number, null);
} else if (TemporalAccessor.class.isAssignableFrom(clazz)) { } else if (TemporalAccessor.class.isAssignableFrom(clazz)) {

View File

@ -206,7 +206,7 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
final Instant instant; final Instant instant;
if (GlobalCustomFormat.FORMAT_SECONDS.equals(this.format)) { if (GlobalCustomFormat.FORMAT_SECONDS.equals(this.format)) {
// https://gitee.com/dromara/hutool/issues/I6IS5B // https://gitee.com/chinabugotech/hutool/issues/I6IS5B
// Unix时间戳 // Unix时间戳
instant = Instant.ofEpochSecond(time); instant = Instant.ofEpochSecond(time);
} else { } else {

View File

@ -561,7 +561,8 @@ public class FileUtil extends PathUtil {
/** /**
* 计算文件的总行数<br> * 计算文件的总行数<br>
* 参考https://stackoverflow.com/questions/453018/number-of-lines-in-a-file-in-java * 参考https://stackoverflow.com/questions/453018/number-of-lines-in-a-file-in-java<br>
* 最后一行如果末尾带有换行符则被当作为新行
* *
* @param file 文件 * @param file 文件
* @param bufferSize 缓存大小小于1则使用默认的1024 * @param bufferSize 缓存大小小于1则使用默认的1024
@ -569,6 +570,20 @@ public class FileUtil extends PathUtil {
* @since 5.8.28 * @since 5.8.28
*/ */
public static int getTotalLines(File file, int bufferSize) { public static int getTotalLines(File file, int bufferSize) {
return getTotalLines(file, bufferSize, true);
}
/**
* 计算文件的总行数<br>
* 参考https://stackoverflow.com/questions/453018/number-of-lines-in-a-file-in-java
*
* @param file 文件
* @param bufferSize 缓存大小小于1则使用默认的1024
* @param lastLineSeparatorAsNewLine 是否将最后一行分隔符作为新行Linux下要求最后一行必须带有换行符不算一行此处用户选择
* @return 该文件总行数
* @since 5.8.37
*/
public static int getTotalLines(File file, int bufferSize, boolean lastLineSeparatorAsNewLine) {
if (false == isFile(file)) { if (false == isFile(file)) {
throw new IORuntimeException("Input must be a File"); throw new IORuntimeException("Input must be a File");
} }
@ -614,9 +629,16 @@ public class FileUtil extends PathUtil {
readChars = is.read(chars); readChars = is.read(chars);
} }
// 最后一个字符为换行符则单独计数行 if(lastLineSeparatorAsNewLine){
if(c == CharUtil.CR){ // 最后一个字符为\r则单独计数行
++count; if(c == CharUtil.CR){
++count;
}
}else{
// 最后一个字符为\n则可选是否算作新行单独计数行
if(c == CharUtil.LF){
--count;
}
} }
return count; return count;
@ -1033,7 +1055,7 @@ public class FileUtil extends PathUtil {
int exceptionsCount = 0; int exceptionsCount = 0;
while (true) { while (true) {
try { try {
// https://github.com/dromara/hutool/issues/3103 // https://github.com/chinabugotech/hutool/issues/3103
//File file = File.createTempFile(prefix, suffix, mkdir(dir)).getCanonicalFile(); //File file = File.createTempFile(prefix, suffix, mkdir(dir)).getCanonicalFile();
final File file = PathUtil.createTempFile(prefix, suffix, null == dir ? null : dir.toPath()).toFile().getCanonicalFile(); final File file = PathUtil.createTempFile(prefix, suffix, null == dir ? null : dir.toPath()).toFile().getCanonicalFile();
if (isReCreat) { if (isReCreat) {
@ -1329,11 +1351,11 @@ public class FileUtil extends PathUtil {
if (null == classPath) { if (null == classPath) {
// throw new NullPointerException("ClassPath is null !"); // throw new NullPointerException("ClassPath is null !");
// 在jar运行模式中ClassPath有可能获取不到此时返回原始相对路径此时获取的文件为相对工作目录 // 在jar运行模式中ClassPath有可能获取不到此时返回原始相对路径此时获取的文件为相对工作目录
return path; return normalPath;
} }
// 资源不存在的情况下使用标准化路径有问题使用原始路径拼接后标准化路径 // 资源不存在的情况下使用标准化路径有问题使用原始路径拼接后标准化路径
return normalize(classPath.concat(Objects.requireNonNull(path))); return normalize(classPath.concat(Objects.requireNonNull(normalPath)));
} }
/** /**

View File

@ -159,7 +159,7 @@ public class FileWriter extends FileWrapper {
} }
/** /**
* 将列表写入文件覆盖模式 * 将列表写入文件覆盖模式最后一行末尾不追加换行符
* *
* @param <T> 集合元素类型 * @param <T> 集合元素类型
* @param list 列表 * @param list 列表
@ -171,7 +171,7 @@ public class FileWriter extends FileWrapper {
} }
/** /**
* 将列表写入文件追加模式 * 将列表写入文件追加模式最后一行末尾不追加换行符
* *
* @param <T> 集合元素类型 * @param <T> 集合元素类型
* @param list 列表 * @param list 列表
@ -183,7 +183,7 @@ public class FileWriter extends FileWrapper {
} }
/** /**
* 将列表写入文件 * 将列表写入文件最后一行末尾不追加换行符
* *
* @param <T> 集合元素类型 * @param <T> 集合元素类型
* @param list 列表 * @param list 列表
@ -196,7 +196,7 @@ public class FileWriter extends FileWrapper {
} }
/** /**
* 将列表写入文件 * 将列表写入文件最后一行末尾不追加换行符
* *
* @param <T> 集合元素类型 * @param <T> 集合元素类型
* @param list 列表 * @param list 列表
@ -207,6 +207,22 @@ public class FileWriter extends FileWrapper {
* @since 3.1.0 * @since 3.1.0
*/ */
public <T> File writeLines(Iterable<T> list, LineSeparator lineSeparator, boolean isAppend) throws IORuntimeException { public <T> File writeLines(Iterable<T> list, LineSeparator lineSeparator, boolean isAppend) throws IORuntimeException {
return writeLines(list, lineSeparator, isAppend, false);
}
/**
* 将列表写入文件
*
* @param <T> 集合元素类型
* @param list 列表
* @param lineSeparator 换行符枚举WindowsMac或Linux换行符
* @param isAppend 是否追加
* @param appendLineSeparator 是否在最后一行末尾追加换行符Linux下要求最后一行必须带有换行符
* @return 目标文件
* @throws IORuntimeException IO异常
* @since 5.8.37
*/
public <T> File writeLines(Iterable<T> list, LineSeparator lineSeparator, boolean isAppend, boolean appendLineSeparator) throws IORuntimeException {
try (PrintWriter writer = getPrintWriter(isAppend)) { try (PrintWriter writer = getPrintWriter(isAppend)) {
boolean isFirst = true; boolean isFirst = true;
for (T t : list) { for (T t : list) {
@ -221,10 +237,12 @@ public class FileWriter extends FileWrapper {
printNewLine(writer, lineSeparator); printNewLine(writer, lineSeparator);
} }
writer.print(t); writer.print(t);
writer.flush();
} }
} }
if(appendLineSeparator){
printNewLine(writer, lineSeparator);
}
writer.flush();
} }
return this.file; return this.file;
} }

View File

@ -17,7 +17,7 @@ import java.util.stream.Stream;
/** /**
* 复制jdk16中的Optional以及自己进行了一点调整和新增比jdk8中的Optional多了几个实用的函数<br> * 复制jdk16中的Optional以及自己进行了一点调整和新增比jdk8中的Optional多了几个实用的函数<br>
* 详细见<a href="https://gitee.com/dromara/hutool/pulls/426">https://gitee.com/dromara/hutool/pulls/426</a> * 详细见<a href="https://gitee.com/chinabugotech/hutool/pulls/426">https://gitee.com/chinabugotech/hutool/pulls/426</a>
* *
* @param <T> 包裹里元素的类型 * @param <T> 包裹里元素的类型
* @author VampireAchao * @author VampireAchao

View File

@ -146,9 +146,9 @@ public interface RegexPool {
* 中国车牌号码兼容新能源车牌 * 中国车牌号码兼容新能源车牌
*/ */
String PLATE_NUMBER = String PLATE_NUMBER =
//https://gitee.com/dromara/hutool/issues/I1B77H?from=project-issue //https://gitee.com/chinabugotech/hutool/issues/I1B77H?from=project-issue
"^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[ABCDEFGHJK])|([ABCDEFGHJK]([A-HJ-NP-Z0-9])[0-9]{4})))|" + "^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[ABCDEFGHJK])|([ABCDEFGHJK]([A-HJ-NP-Z0-9])[0-9]{4})))|" +
//https://gitee.com/dromara/hutool/issues/I1BJHE?from=project-issue //https://gitee.com/chinabugotech/hutool/issues/I1BJHE?from=project-issue
"([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领]\\d{3}\\d{1,3}[领])|" + "([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领]\\d{3}\\d{1,3}[领])|" +
"([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$"; "([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$";

View File

@ -2,8 +2,10 @@ package cn.hutool.core.lang.reflect;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.TypeUtil; import cn.hutool.core.util.TypeUtil;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable; import java.lang.reflect.TypeVariable;
@ -37,14 +39,14 @@ public class ActualTypeMapperPool {
* @return 泛型对应关系Map * @return 泛型对应关系Map
* @since 5.7.16 * @since 5.7.16
*/ */
public static Map<String, Type> getStrKeyMap(Type type){ public static Map<String, Type> getStrKeyMap(Type type) {
return Convert.toMap(String.class, Type.class, get(type)); return Convert.toMap(String.class, Type.class, get(type));
} }
/** /**
* 获得泛型变量对应的泛型实际类型如果此变量没有对应的实际类型返回null * 获得泛型变量对应的泛型实际类型如果此变量没有对应的实际类型返回null
* *
* @param type * @param type
* @param typeVariable 泛型变量例如T等 * @param typeVariable 泛型变量例如T等
* @return 实际类型可能为Class等 * @return 实际类型可能为Class等
*/ */
@ -57,11 +59,35 @@ public class ActualTypeMapperPool {
return result; return result;
} }
/**
* 获得泛型变量对应的泛型实际类型如果此变量没有对应的实际类型返回null
*
* @param type
* @param genericArrayType 泛型数组类型
* @return 实际类型可能为Class等
* @since 5.8.37
*/
public static Type getActualType(Type type, GenericArrayType genericArrayType) {
final Map<Type, Type> typeTypeMap = get(type);
Type actualType = typeTypeMap.get(genericArrayType);
if (actualType == null) {
Type componentType = typeTypeMap.get(genericArrayType.getGenericComponentType());
if (!(componentType instanceof Class<?>)) {
return null;
}
actualType = ArrayUtil.getArrayType((Class<?>) componentType);
typeTypeMap.put(genericArrayType, actualType);
}
return actualType;
}
/** /**
* 获取指定泛型变量对应的真实类型<br> * 获取指定泛型变量对应的真实类型<br>
* 由于子类中泛型参数实现和父类接口中泛型定义位置是一一对应的因此可以通过对应关系找到泛型实现类型<br> * 由于子类中泛型参数实现和父类接口中泛型定义位置是一一对应的因此可以通过对应关系找到泛型实现类型<br>
* *
* @param type 真实类型所在类此类中记录了泛型参数对应的实际类型 * @param type 真实类型所在类此类中记录了泛型参数对应的实际类型
* @param typeVariables 泛型变量需要的实际类型对应的泛型参数 * @param typeVariables 泛型变量需要的实际类型对应的泛型参数
* @return 给定泛型参数对应的实际类型如果无对应类型对应位置返回null * @return 给定泛型参数对应的实际类型如果无对应类型对应位置返回null
*/ */
@ -70,8 +96,8 @@ public class ActualTypeMapperPool {
final Type[] result = new Type[typeVariables.length]; final Type[] result = new Type[typeVariables.length];
for (int i = 0; i < typeVariables.length; i++) { for (int i = 0; i < typeVariables.length; i++) {
result[i] = (typeVariables[i] instanceof TypeVariable) result[i] = (typeVariables[i] instanceof TypeVariable)
? getActualType(type, (TypeVariable<?>) typeVariables[i]) ? getActualType(type, (TypeVariable<?>) typeVariables[i])
: typeVariables[i]; : typeVariables[i];
} }
return result; return result;
} }
@ -94,7 +120,7 @@ public class ActualTypeMapperPool {
// 如果传入的非Class例如TypeReference获取到泛型参数中实际的泛型对象类继续按照类处理 // 如果传入的非Class例如TypeReference获取到泛型参数中实际的泛型对象类继续按照类处理
while (null != type) { while (null != type) {
final ParameterizedType parameterizedType = TypeUtil.toParameterizedType(type); final ParameterizedType parameterizedType = TypeUtil.toParameterizedType(type);
if(null == parameterizedType){ if (null == parameterizedType) {
break; break;
} }
final Type[] typeArguments = parameterizedType.getActualTypeArguments(); final Type[] typeArguments = parameterizedType.getActualTypeArguments();
@ -105,7 +131,7 @@ public class ActualTypeMapperPool {
for (int i = 0; i < typeParameters.length; i++) { for (int i = 0; i < typeParameters.length; i++) {
value = typeArguments[i]; value = typeArguments[i];
// 跳过泛型变量对应泛型变量的情况 // 跳过泛型变量对应泛型变量的情况
if(false == value instanceof TypeVariable){ if (false == value instanceof TypeVariable) {
typeMap.put(typeParameters[i], value); typeMap.put(typeParameters[i], value);
} }
} }

View File

@ -10,7 +10,7 @@ import java.util.Stack;
/** /**
* 数学表达式计算工具类<br> * 数学表达式计算工具类<br>
* https://github.com/dromara/hutool/issues/1090#issuecomment-693750140 * https://github.com/chinabugotech/hutool/issues/1090#issuecomment-693750140
* *
* @author trainliang, looly * @author trainliang, looly
* @since 5.4.3 * @since 5.4.3

View File

@ -11,7 +11,7 @@ import java.util.Currency;
/** /**
* 单币种货币类处理货币算术币种和取整 * 单币种货币类处理货币算术币种和取整
* <p> * <p>
* 感谢提供此方法的用户https://github.com/dromara/hutool/issues/605 * 感谢提供此方法的用户https://github.com/chinabugotech/hutool/issues/605
* *
* <p> * <p>
* 货币类中封装了货币金额和币种目前金额在内部是long类型表示 * 货币类中封装了货币金额和币种目前金额在内部是long类型表示

View File

@ -518,7 +518,7 @@ public class NetUtil {
* <p> * <p>
* 此方法不会抛出异常获取失败将返回{@code null}<br> * 此方法不会抛出异常获取失败将返回{@code null}<br>
* <p> * <p>
* https://github.com/dromara/hutool/issues/428 * https://github.com/chinabugotech/hutool/issues/428
* *
* @return 本机网卡IP地址获取失败返回{@code null} * @return 本机网卡IP地址获取失败返回{@code null}
* @since 3.0.1 * @since 3.0.1

View File

@ -363,7 +363,7 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
@Override @Override
public void close() { public void close() {
if(this.config.endingLineBreak){ if(this.config.endingLineBreak){
//https://gitee.com/dromara/hutool/issues/I75K5G //https://gitee.com/chinabugotech/hutool/issues/I75K5G
writeLine(); writeLine();
} }
IoUtil.close(this.writer); IoUtil.close(this.writer);

View File

@ -340,6 +340,11 @@ public class IdcardUtil {
if (StrUtil.isBlank(idcard)) { if (StrUtil.isBlank(idcard)) {
return null; return null;
} }
// issue#IBP6T1 中文空格替换为英文
idcard = StrUtil.replace(idcard, "", "(");
idcard = StrUtil.replace(idcard, "", ")");
String[] info = new String[3]; String[] info = new String[3];
String card = idcard.replaceAll("[()]", ""); String card = idcard.replaceAll("[()]", "");
if (card.length() != 8 && card.length() != 9 && idcard.length() != 10) { if (card.length() != 8 && card.length() != 9 && idcard.length() != 10) {

View File

@ -3,12 +3,7 @@ package cn.hutool.core.util;
import cn.hutool.core.lang.ParameterizedTypeImpl; import cn.hutool.core.lang.ParameterizedTypeImpl;
import cn.hutool.core.lang.reflect.ActualTypeMapperPool; import cn.hutool.core.lang.reflect.ActualTypeMapperPool;
import java.lang.reflect.Field; import java.lang.reflect.*;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -412,6 +407,13 @@ public class TypeUtil {
if (typeVariable instanceof TypeVariable) { if (typeVariable instanceof TypeVariable) {
return ActualTypeMapperPool.getActualType(type, (TypeVariable<?>) typeVariable); return ActualTypeMapperPool.getActualType(type, (TypeVariable<?>) typeVariable);
} }
if (typeVariable instanceof GenericArrayType) {
//return ActualTypeMapperPool.getActualType(type, (GenericArrayType) typeVariable);
final Type actualType = ActualTypeMapperPool.getActualType(type, (GenericArrayType) typeVariable);
if(null != actualType){
return actualType;
}
}
// 没有需要替换的泛型变量原样输出 // 没有需要替换的泛型变量原样输出
return typeVariable; return typeVariable;

View File

@ -0,0 +1,196 @@
package cn.hutool.core.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.UtilException;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 版本对比工具
* {@link cn.hutool.core.comparator.VersionComparator} 的封装
* 最主要功能包括
*
*
* <pre>
* 1. 版本表达式匹配
* 2. 单个版本匹配
* </pre>
*
* @author winlans
* @see cn.hutool.core.comparator.VersionComparator
*/
public class VersionUtil {
private static final Pattern COMPARE_REG = Pattern.compile("^[<>≥≤]=?");
// 默认多版本分隔符
private static final String defaultVersionsDelimiter = ";";
/**
* 是否匹配任意一个版本
*
* @param currentVersion 当前版本
* @param compareVersions 待匹配的版本列表
* @return true 包含待匹配的版本
*/
public static boolean anyMatch(String currentVersion, Collection<String> compareVersions) {
return matchEl(currentVersion, CollUtil.join(compareVersions, defaultVersionsDelimiter));
}
public static boolean anyMatch(String currentVersion, String... compareVersions) {
return matchEl(currentVersion, ArrayUtil.join(compareVersions, defaultVersionsDelimiter));
}
/**
* 当前版本大于待比较版本
*
* @param currentVersion 当前本本
* @param compareVersion 待比较版本
* @return true 当前版本大于待比较版本
*/
public static boolean isGreaterThan(String currentVersion, String compareVersion) {
return matchEl(currentVersion, ">" + compareVersion);
}
/**
* 当前版本大于等于待比较版本
*
* @param currentVersion 当前本本
* @param compareVersion 待比较版本
* @return true 当前版本大于等于待比较版本
*/
public static boolean isGreaterThanOrEqual(String currentVersion, String compareVersion) {
return matchEl(currentVersion, ">=" + compareVersion);
}
/**
* 当前版本小于待比较版本
*
* @param currentVersion 当前本本
* @param compareVersion 待比较版本
* @return true 当前版本小于待比较版本
*/
public static boolean isLessThan(String currentVersion, String compareVersion) {
return matchEl(currentVersion, "<" + compareVersion);
}
/**
* 当前版本小于等于待比较版本
*
* @param currentVersion 当前本本
* @param compareVersion 待比较版本
* @return true 当前版本小于等于待比较版本
*/
public static boolean isLessThanOrEqual(String currentVersion, String compareVersion) {
return matchEl(currentVersion, "<=" + compareVersion);
}
/**
* 当前版本是否满足版本表达式
* <pre>
* matchEl("1.0.2", ">=1.0.2") == true
* matchEl("1.0.2", "<1.0.1;1.0.2") == true
* matchEl("1.0.2", "<1.0.2") == false
* matchEl("1.0.2", "1.0.0-1.1.1") == true
* matchEl("1.0.2", "1.0.0-1.1.1") == true
* </pre>
*
* @param currentVersion 当前本本
* @param versionEl 版本表达式
* @return true 当前版本小于等于待比较版本
*/
public static boolean matchEl(String currentVersion, String versionEl) {
return matchEl(currentVersion, versionEl, defaultVersionsDelimiter);
}
/**
* 当前版本是否满足版本表达式
* <pre>
* matchEl("1.0.2", ">=1.0.2", ";") == true
* matchEl("1.0.2", "<1.0.1,1.0.2", ",") == true
* matchEl("1.0.2", "<1.0.2", ";") == false
* matchEl("1.0.2", "1.0.0-1.1.1", ",") == true
* matchEl("1.0.2", "1.0.1,1.0.2-1.1.1", ",") == true
* </pre>
*
* @param currentVersion 当前本本
* @param versionEl 版本表达式可以匹配多个条件使用指定的分隔符默认;分隔,
* {@code '-'}表示范围包含左右版本,如果 {@code '-'}的左边没有表示小于等于某个版本号 右边表示大于等于某个版本号
* 支持比较符号{@code '>'},{@code '<'}, {@code '>='},{@code '<='}{@code '≤'}{@code '≥'}
*
* <ul>
* <li>{@code 1.0.1-1.2.4, 1.9.8} 表示版本号 大于等于{@code 1.0.1}且小于等于{@code 1.2.4} 版本{@code 1.9.8}</li>
* <li>{@code >=2.0.0, 1.9.8} 表示版本号 大于等于{@code 2.0.0} 版本{@code 1.9.8}</li>
* </ul>
* @param versionsDelimiter 多表达式分隔符
* @return true 当前版本小于等于待比较版本
*/
public static boolean matchEl(String currentVersion, String versionEl, String versionsDelimiter) {
if (StrUtil.isBlank(versionsDelimiter)
|| StrUtil.equals("-", versionsDelimiter)
|| ReUtil.isMatch(COMPARE_REG, versionsDelimiter)) {
throw new UtilException("非法的版本分隔符:" + versionsDelimiter);
}
if (StrUtil.isBlank(versionEl) || StrUtil.isBlank(currentVersion)) {
return false;
}
String trimmedVersion = StrUtil.trim(currentVersion);
List<String> els = StrUtil.split(versionEl, versionsDelimiter, true, true);
if (CollUtil.isEmpty(els)) {
return false;
}
for (String el : els) {
el = el.trim();
Matcher matcher = COMPARE_REG.matcher(el);
if (matcher.find()) {
String op = matcher.group();
String ver = StrUtil.removePrefix(el, op);
switch (op) {
case ">=":
case "":
if (StrUtil.compareVersion(trimmedVersion, ver) >= 0) {
return true;
}
break;
case "<=":
case "":
if (StrUtil.compareVersion(trimmedVersion, ver) <= 0) {
return true;
}
break;
case "<":
if (StrUtil.compareVersion(trimmedVersion, ver) < 0) {
return true;
}
break;
case ">":
if (StrUtil.compareVersion(trimmedVersion, ver) > 0) {
return true;
}
break;
default:
return false;
}
} else if (StrUtil.contains(el, "-")) {
String[] pair = el.split("-");
String left = StrUtil.blankToDefault(StrUtil.trim(pair[0]), "");
String right = StrUtil.blankToDefault(StrUtil.trim(pair[1]), "");
boolean leftMatch = StrUtil.isBlank(left) || StrUtil.compareVersion(left, trimmedVersion) <= 0;
boolean rightMatch = StrUtil.isBlank(right) || StrUtil.compareVersion(right, trimmedVersion) >= 0;
if (leftMatch && rightMatch) {
return true;
}
} else if (Objects.equals(trimmedVersion, el)) {
return true;
}
}
return false;
}
}

View File

@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test;
public class BeanCopyMappingTest { public class BeanCopyMappingTest {
/** /**
* https://gitee.com/dromara/hutool/issues/I4C48U <br> * https://gitee.com/chinabugotech/hutool/issues/I4C48U <br>
* 传递复制不要用注解别名应该用动态映射 * 传递复制不要用注解别名应该用动态映射
*/ */
@Test @Test

View File

@ -253,7 +253,7 @@ public class BeanUtilTest {
final SubPersonWithAlias subPersonWithAlias = BeanUtil.toBean(map, SubPersonWithAlias.class); final SubPersonWithAlias subPersonWithAlias = BeanUtil.toBean(map, SubPersonWithAlias.class);
assertEquals("sub名字", subPersonWithAlias.getSubName()); assertEquals("sub名字", subPersonWithAlias.getSubName());
//https://gitee.com/dromara/hutool/issues/I6H0XF //https://gitee.com/chinabugotech/hutool/issues/I6H0XF
assertFalse(subPersonWithAlias.isBooleana()); assertFalse(subPersonWithAlias.isBooleana());
assertNull(subPersonWithAlias.getBooleanb()); assertNull(subPersonWithAlias.getBooleanb());
} }
@ -520,7 +520,7 @@ public class BeanUtilTest {
} }
/** /**
* <a href="https://github.com/dromara/hutool/issues/1173">#1173</a> * <a href="https://github.com/chinabugotech/hutool/issues/1173">#1173</a>
*/ */
@Test @Test
public void beanToBeanOverlayFieldTest() { public void beanToBeanOverlayFieldTest() {
@ -597,7 +597,7 @@ public class BeanUtilTest {
@Test @Test
public void copyBeanPropertiesFunctionFilterTest() { public void copyBeanPropertiesFunctionFilterTest() {
//https://gitee.com/dromara/hutool/pulls/590 //https://gitee.com/chinabugotech/hutool/pulls/590
final Person o = new Person(); final Person o = new Person();
o.setName("asd"); o.setName("asd");
o.setAge(123); o.setAge(123);
@ -858,7 +858,7 @@ public class BeanUtilTest {
@Test @Test
public void valueProviderToBeanTest() { public void valueProviderToBeanTest() {
// https://gitee.com/dromara/hutool/issues/I5B4R7 // https://gitee.com/chinabugotech/hutool/issues/I5B4R7
final CopyOptions copyOptions = CopyOptions.create(); final CopyOptions copyOptions = CopyOptions.create();
final Map<String, String> filedMap = new HashMap<>(); final Map<String, String> filedMap = new HashMap<>();
filedMap.put("name", "sourceId"); filedMap.put("name", "sourceId");
@ -931,7 +931,7 @@ public class BeanUtilTest {
@Test @Test
public void hasGetterTest() { public void hasGetterTest() {
// https://gitee.com/dromara/hutool/issues/I6M7Z7 // https://gitee.com/chinabugotech/hutool/issues/I6M7Z7
final boolean b = BeanUtil.hasGetter(Object.class); final boolean b = BeanUtil.hasGetter(Object.class);
assertFalse(b); assertFalse(b);
} }

View File

@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test;
import java.io.Serializable; import java.io.Serializable;
/** /**
* https://github.com/dromara/hutool/issues/1687 * https://github.com/chinabugotech/hutool/issues/1687
*/ */
public class Issue1687Test { public class Issue1687Test {

View File

@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* https://github.com/dromara/hutool/issues/2009 * https://github.com/chinabugotech/hutool/issues/2009
*/ */
public class Issue2009Test { public class Issue2009Test {

View File

@ -5,7 +5,7 @@ import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* https://github.com/dromara/hutool/issues/2082<br> * https://github.com/chinabugotech/hutool/issues/2082<br>
* 当setXXX有重载方法的时候BeanDesc中会匹配到重载方法增加类型检查来规避之 * 当setXXX有重载方法的时候BeanDesc中会匹配到重载方法增加类型检查来规避之
*/ */
public class Issue2082Test { public class Issue2082Test {

View File

@ -12,7 +12,7 @@ import java.util.Map;
public class Issue2202Test { public class Issue2202Test {
/** /**
* https://github.com/dromara/hutool/issues/2202 * https://github.com/chinabugotech/hutool/issues/2202
*/ */
@Test @Test
public void mapToBeanWithFieldNameEditorTest(){ public void mapToBeanWithFieldNameEditorTest(){

View File

@ -8,7 +8,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* https://github.com/dromara/hutool/issues/2697 * https://github.com/chinabugotech/hutool/issues/2697
*/ */
public class Issue2697Test { public class Issue2697Test {

View File

@ -854,7 +854,7 @@ public class CollUtilTest {
@Test @Test
public void setValueByMapTest() { public void setValueByMapTest() {
// https://gitee.com/dromara/hutool/pulls/482 // https://gitee.com/chinabugotech/hutool/pulls/482
final List<Person> people = Arrays.asList( final List<Person> people = Arrays.asList(
new Person("aa", 12, "man", 1), new Person("aa", 12, "man", 1),
new Person("bb", 13, "woman", 2), new Person("bb", 13, "woman", 2),

View File

@ -12,7 +12,7 @@ public class IssueI5DRU0Test {
@Test @Test
@Disabled @Disabled
public void appendTest(){ public void appendTest(){
// https://gitee.com/dromara/hutool/issues/I5DRU0 // https://gitee.com/chinabugotech/hutool/issues/I5DRU0
// 向zip中添加文件的时候如果添加的文件的父目录已经存在会报错实际中目录存在忽略即可 // 向zip中添加文件的时候如果添加的文件的父目录已经存在会报错实际中目录存在忽略即可
ZipUtil.append(Paths.get("d:/test/zipTest.zip"), Paths.get("d:/test/zipTest"), StandardCopyOption.REPLACE_EXISTING); ZipUtil.append(Paths.get("d:/test/zipTest.zip"), Paths.get("d:/test/zipTest"), StandardCopyOption.REPLACE_EXISTING);
} }

View File

@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test;
import java.io.File; import java.io.File;
/** /**
* https://gitee.com/dromara/hutool/issues/IAGYDG * https://gitee.com/chinabugotech/hutool/issues/IAGYDG
*/ */
public class IssueIAGYDGTest { public class IssueIAGYDGTest {
@Test @Test

View File

@ -351,7 +351,7 @@ public class ConvertTest {
@Test @Test
public void toBigDecimalTest() { public void toBigDecimalTest() {
// https://github.com/dromara/hutool/issues/1818 // https://github.com/chinabugotech/hutool/issues/1818
final String str = "33020000210909112800000124"; final String str = "33020000210909112800000124";
final BigDecimal bigDecimal = Convert.toBigDecimal(str); final BigDecimal bigDecimal = Convert.toBigDecimal(str);
assertEquals(str, bigDecimal.toPlainString()); assertEquals(str, bigDecimal.toPlainString());
@ -359,7 +359,7 @@ public class ConvertTest {
@Test @Test
public void toFloatTest() { public void toFloatTest() {
// https://gitee.com/dromara/hutool/issues/I4M0E4 // https://gitee.com/chinabugotech/hutool/issues/I4M0E4
final String hex2 = "CD0CCB43"; final String hex2 = "CD0CCB43";
final byte[] value = HexUtil.decodeHex(hex2); final byte[] value = HexUtil.decodeHex(hex2);
final float f = Convert.toFloat(value); final float f = Convert.toFloat(value);

View File

@ -25,7 +25,7 @@ public class CalendarUtilTest {
final Calendar calendar = CalendarUtil.parse("2021-09-27 00:00:112323", false, final Calendar calendar = CalendarUtil.parse("2021-09-27 00:00:112323", false,
DatePattern.NORM_DATETIME_FORMAT); DatePattern.NORM_DATETIME_FORMAT);
// https://github.com/dromara/hutool/issues/1849 // https://github.com/chinabugotech/hutool/issues/1849
// 在使用严格模式时秒不正确抛出异常 // 在使用严格模式时秒不正确抛出异常
DateUtil.date(calendar); DateUtil.date(calendar);
}); });

View File

@ -117,7 +117,7 @@ public class ChineseDateTest {
@Test @Test
public void getChineseMonthTest2(){ public void getChineseMonthTest2(){
//https://github.com/dromara/hutool/issues/2112 //https://github.com/chinabugotech/hutool/issues/2112
ChineseDate springFestival = new ChineseDate(DateUtil.parseDate("2022-02-01")); ChineseDate springFestival = new ChineseDate(DateUtil.parseDate("2022-02-01"));
final String chineseMonth = springFestival.getChineseMonth(); final String chineseMonth = springFestival.getChineseMonth();
assertEquals("一月", chineseMonth); assertEquals("一月", chineseMonth);
@ -125,7 +125,7 @@ public class ChineseDateTest {
@Test @Test
public void day19700101Test(){ public void day19700101Test(){
// https://gitee.com/dromara/hutool/issues/I4UTPK // https://gitee.com/chinabugotech/hutool/issues/I4UTPK
Date date = DateUtil.parse("1970-01-01"); Date date = DateUtil.parse("1970-01-01");
//noinspection ConstantConditions //noinspection ConstantConditions
ChineseDate chineseDate = new ChineseDate(date); ChineseDate chineseDate = new ChineseDate(date);
@ -153,7 +153,7 @@ public class ChineseDateTest {
@Test @Test
public void getGregorianDateTest(){ public void getGregorianDateTest(){
// https://gitee.com/dromara/hutool/issues/I4ZSGJ // https://gitee.com/chinabugotech/hutool/issues/I4ZSGJ
ChineseDate chineseDate = new ChineseDate(1998, 5, 1); ChineseDate chineseDate = new ChineseDate(1998, 5, 1);
assertEquals("1998-06-24 00:00:00", chineseDate.getGregorianDate().toString()); assertEquals("1998-06-24 00:00:00", chineseDate.getGregorianDate().toString());

View File

@ -1002,7 +1002,7 @@ public class DateUtilTest {
@Test @Test
public void parseNotFitTest() { public void parseNotFitTest() {
//https://github.com/dromara/hutool/issues/1332 //https://github.com/chinabugotech/hutool/issues/1332
assertThrows(DateException.class, () -> { assertThrows(DateException.class, () -> {
// 在日期格式不匹配的时候测试是否正常报错 // 在日期格式不匹配的时候测试是否正常报错
DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN); DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN);

View File

@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test;
public class Issue2981Test { public class Issue2981Test {
/** /**
* https://github.com/dromara/hutool/issues/2981<br> * https://github.com/chinabugotech/hutool/issues/2981<br>
* 按照ISO8601规范以Z结尾表示UTC时间否则为当地时间 * 按照ISO8601规范以Z结尾表示UTC时间否则为当地时间
*/ */
@SuppressWarnings("DataFlowIssue") @SuppressWarnings("DataFlowIssue")

View File

@ -8,7 +8,7 @@ import java.util.Calendar;
public class Issue3011Test { public class Issue3011Test {
@Test @Test
public void isSameMonthTest() { public void isSameMonthTest() {
// https://github.com/dromara/hutool/issues/3011 // https://github.com/chinabugotech/hutool/issues/3011
// 判断是否同一个月还需考虑公元前和公元后的的情况 // 判断是否同一个月还需考虑公元前和公元后的的情况
// 此处公元前2020年和公元2021年返回年都是2021 // 此处公元前2020年和公元2021年返回年都是2021
final Calendar calendar1 = Calendar.getInstance(); final Calendar calendar1 = Calendar.getInstance();

View File

@ -52,7 +52,7 @@ public class FileCopierTest {
@Test @Test
@Disabled @Disabled
public void copyFileByRelativePath(){ public void copyFileByRelativePath(){
// https://github.com/dromara/hutool/pull/2188 // https://github.com/chinabugotech/hutool/pull/2188
// 当复制的目标文件位置是相对路径的时候可以通过 // 当复制的目标文件位置是相对路径的时候可以通过
FileCopier copier = FileCopier.create(new File("pom.xml"),new File("aaa.txt")); FileCopier copier = FileCopier.create(new File("pom.xml"),new File("aaa.txt"));
copier.copy(); copier.copy();

View File

@ -76,7 +76,7 @@ public class FileTypeUtilTest {
@Test @Test
@Disabled @Disabled
public void webpTest(){ public void webpTest(){
// https://gitee.com/dromara/hutool/issues/I5BGTF // https://gitee.com/chinabugotech/hutool/issues/I5BGTF
final File file = FileUtil.file("d:/test/a.webp"); final File file = FileUtil.file("d:/test/a.webp");
final BufferedInputStream inputStream = FileUtil.getInputStream(file); final BufferedInputStream inputStream = FileUtil.getInputStream(file);
final String type = FileTypeUtil.getType(inputStream); final String type = FileTypeUtil.getType(inputStream);

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.file.LineSeparator; import cn.hutool.core.io.file.LineSeparator;
import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Console;
import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.CharsetUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -538,22 +539,31 @@ public class FileUtilTest {
@Test @Test
public void getTotalLinesTest() { public void getTotalLinesTest() {
// 此文件最后一行有换行符则最后的空行算作一行 // 此文件最后一行有换行符则最后的空行算作一行
final int totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines.csv")); int totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines.csv"));
assertEquals(8, totalLines); assertEquals(8, totalLines);
totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines.csv"), -1, false);
Assertions.assertEquals(7, totalLines);
} }
@Test @Test
public void getTotalLinesCrTest() { public void getTotalLinesCrTest() {
// 此文件最后一行有换行符则最后的空行算作一行 // 此文件最后一行有换行符则最后的空行算作一行
final int totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines_cr.csv")); int totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines_cr.csv"));
assertEquals(8, totalLines); assertEquals(8, totalLines);
totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines_cr.csv"), -1, false);
Assertions.assertEquals(7, totalLines);
} }
@Test @Test
public void getTotalLinesCrlfTest() { public void getTotalLinesCrlfTest() {
// 此文件最后一行有换行符则最后的空行算作一行 // 此文件最后一行有换行符则最后的空行算作一行
final int totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines_crlf.csv")); int totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines_crlf.csv"));
assertEquals(8, totalLines); assertEquals(8, totalLines);
totalLines = FileUtil.getTotalLines(FileUtil.file("test_lines_crlf.csv"), -1, false);
Assertions.assertEquals(7, totalLines);
} }
@Test @Test

View File

@ -0,0 +1,24 @@
package cn.hutool.core.io.file;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class FileWriterTest {
@Test
@Disabled
void writeLinesAppendLineSeparatorTest() {
final FileWriter writer = FileWriter.create(FileUtil.file("d:/test/lines_append_line_separator.txt"));
writer.writeLines(ListUtil.of("aaa", "bbb", "ccc"), null, false, true);
}
@Test
@Disabled
void writeLinesTest() {
final FileWriter writer = FileWriter.create(FileUtil.file("d:/test/lines.txt"));
writer.writeLines(ListUtil.of("aaa", "bbb", "ccc"), null, false);
}
}

View File

@ -8,7 +8,7 @@ import java.io.File;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* https://gitee.com/dromara/hutool/issues/IAB65V * https://gitee.com/chinabugotech/hutool/issues/IAB65V
*/ */
public class IssueIAB65VTest { public class IssueIAB65VTest {
@Test @Test

View File

@ -10,7 +10,7 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* https://gitee.com/dromara/hutool/pulls/532 * https://gitee.com/chinabugotech/hutool/pulls/532
*/ */
public class MetroHashTest { public class MetroHashTest {

View File

@ -7,7 +7,7 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* https://gitee.com/dromara/hutool/pulls/447/files * https://gitee.com/chinabugotech/hutool/pulls/447/files
* *
* TODO 同时继承泛型和实现泛型接口需要解析此处为F * TODO 同时继承泛型和实现泛型接口需要解析此处为F
*/ */

View File

@ -28,7 +28,7 @@ public class CaseInsensitiveMapTest {
@Test @Test
public void mergeTest(){ public void mergeTest(){
//https://github.com/dromara/hutool/issues/2086 //https://github.com/chinabugotech/hutool/issues/2086
Pair<String, String> b = new Pair<>("a", "value"); Pair<String, String> b = new Pair<>("a", "value");
Pair<String, String> a = new Pair<>("A", "value"); Pair<String, String> a = new Pair<>("A", "value");
final CaseInsensitiveMap<Object, Object> map = new CaseInsensitiveMap<>(); final CaseInsensitiveMap<Object, Object> map = new CaseInsensitiveMap<>();

View File

@ -32,7 +32,7 @@ public class CalculatorTest {
@Test @Test
public void conversationTest5(){ public void conversationTest5(){
// https://github.com/dromara/hutool/issues/1984 // https://github.com/chinabugotech/hutool/issues/1984
final double conversion = Calculator.conversion("((1/1) / (1/1) -1) * 100"); final double conversion = Calculator.conversion("((1/1) / (1/1) -1) * 100");
assertEquals(0, conversion, 0); assertEquals(0, conversion, 0);
} }
@ -45,14 +45,14 @@ public class CalculatorTest {
@Test @Test
public void conversationTest7() { public void conversationTest7() {
//https://gitee.com/dromara/hutool/issues/I4KONB //https://gitee.com/chinabugotech/hutool/issues/I4KONB
final double conversion = Calculator.conversion("((-2395+0) * 0.3+140.24+35+90)/30"); final double conversion = Calculator.conversion("((-2395+0) * 0.3+140.24+35+90)/30");
assertEquals(-15.11, conversion, 0.01); assertEquals(-15.11, conversion, 0.01);
} }
@Test @Test
public void issue2964Test() { public void issue2964Test() {
// https://github.com/dromara/hutool/issues/2964 // https://github.com/chinabugotech/hutool/issues/2964
final double calcValue = Calculator.conversion("(11+2)12"); final double calcValue = Calculator.conversion("(11+2)12");
assertEquals(156D, calcValue, 0.001); assertEquals(156D, calcValue, 0.001);
} }

View File

@ -26,7 +26,7 @@ public class UrlBuilderTest {
@Test @Test
public void buildWithoutSlashTest() { public void buildWithoutSlashTest() {
// https://github.com/dromara/hutool/issues/2459 // https://github.com/chinabugotech/hutool/issues/2459
String buildUrl = UrlBuilder.of().setScheme("http").setHost("192.168.1.1").setPort(8080).setWithEndTag(false).build(); String buildUrl = UrlBuilder.of().setScheme("http").setHost("192.168.1.1").setPort(8080).setWithEndTag(false).build();
assertEquals("http://192.168.1.1:8080", buildUrl); assertEquals("http://192.168.1.1:8080", buildUrl);
@ -279,7 +279,7 @@ public class UrlBuilderTest {
@Test @Test
public void encodePathTest2() { public void encodePathTest2() {
// https://gitee.com/dromara/hutool/issues/I4RA42 // https://gitee.com/chinabugotech/hutool/issues/I4RA42
// Path中`:`在第一个segment需要转义之后的不需要 // Path中`:`在第一个segment需要转义之后的不需要
final String urlStr = "https://hutool.cn/aa/bb/Pre-K,Kindergarten,First,Second,Third,Fourth,Fifth/Page:3"; final String urlStr = "https://hutool.cn/aa/bb/Pre-K,Kindergarten,First,Second,Third,Fourth,Fifth/Page:3";
final UrlBuilder urlBuilder = UrlBuilder.ofHttp(urlStr, CharsetUtil.CHARSET_UTF_8); final UrlBuilder urlBuilder = UrlBuilder.ofHttp(urlStr, CharsetUtil.CHARSET_UTF_8);
@ -298,7 +298,7 @@ public class UrlBuilderTest {
@Test @Test
public void fragmentEncodeTest() { public void fragmentEncodeTest() {
// https://gitee.com/dromara/hutool/issues/I49KAL // https://gitee.com/chinabugotech/hutool/issues/I49KAL
// https://stackoverflow.com/questions/26088849/url-fragment-allowed-characters // https://stackoverflow.com/questions/26088849/url-fragment-allowed-characters
final String url = "https://hutool.cn/docs/#/?id=简介"; final String url = "https://hutool.cn/docs/#/?id=简介";
UrlBuilder urlBuilder = UrlBuilder.ofHttp(url); UrlBuilder urlBuilder = UrlBuilder.ofHttp(url);
@ -310,7 +310,7 @@ public class UrlBuilderTest {
@Test @Test
public void slashEncodeTest() { public void slashEncodeTest() {
// https://github.com/dromara/hutool/issues/1904 // https://github.com/chinabugotech/hutool/issues/1904
// 在query中"/"是不可转义字符 // 在query中"/"是不可转义字符
// https://www.rfc-editor.org/rfc/rfc3986.html#section-3.4 // https://www.rfc-editor.org/rfc/rfc3986.html#section-3.4
final String url = "https://invoice.maycur.com/2b27a802-8423-4d41-86f5-63a6b259f61e.xlsx?download/2b27a802-8423-4d41-86f5-63a6b259f61e.xlsx&e=1630491088"; final String url = "https://invoice.maycur.com/2b27a802-8423-4d41-86f5-63a6b259f61e.xlsx?download/2b27a802-8423-4d41-86f5-63a6b259f61e.xlsx&e=1630491088";
@ -333,7 +333,7 @@ public class UrlBuilderTest {
@Test @Test
public void addPathEncodeTest2() { public void addPathEncodeTest2() {
// https://github.com/dromara/hutool/issues/1912 // https://github.com/chinabugotech/hutool/issues/1912
final String url = UrlBuilder.of() final String url = UrlBuilder.of()
.setScheme("https") .setScheme("https")
.setHost("domain.cn") .setHost("domain.cn")
@ -359,7 +359,7 @@ public class UrlBuilderTest {
@Test @Test
public void fragmentTest() { public void fragmentTest() {
// https://gitee.com/dromara/hutool/issues/I49KAL#note_8060874 // https://gitee.com/chinabugotech/hutool/issues/I49KAL#note_8060874
final String url = "https://www.hutool.cn/#/a/b?timestamp=1640391380204"; final String url = "https://www.hutool.cn/#/a/b?timestamp=1640391380204";
final UrlBuilder builder = UrlBuilder.ofHttp(url); final UrlBuilder builder = UrlBuilder.ofHttp(url);
@ -368,7 +368,7 @@ public class UrlBuilderTest {
@Test @Test
public void fragmentAppendParamTest() { public void fragmentAppendParamTest() {
// https://gitee.com/dromara/hutool/issues/I49KAL#note_8060874 // https://gitee.com/chinabugotech/hutool/issues/I49KAL#note_8060874
final String url = "https://www.hutool.cn/#/a/b"; final String url = "https://www.hutool.cn/#/a/b";
final UrlBuilder builder = UrlBuilder.ofHttp(url); final UrlBuilder builder = UrlBuilder.ofHttp(url);
builder.setFragment(builder.getFragment() + "?timestamp=1640391380204"); builder.setFragment(builder.getFragment() + "?timestamp=1640391380204");
@ -437,7 +437,7 @@ public class UrlBuilderTest {
@Test @Test
public void issue2243Test() { public void issue2243Test() {
// https://github.com/dromara/hutool/issues/2243 // https://github.com/chinabugotech/hutool/issues/2243
// 如果用户已经做了%编码不应该重复编码 // 如果用户已经做了%编码不应该重复编码
final String url = "https://hutool.cn/v1.0?privateNum=%2B8616512884988"; final String url = "https://hutool.cn/v1.0?privateNum=%2B8616512884988";
final String s = UrlBuilder.of(url, null).setCharset(CharsetUtil.CHARSET_UTF_8).toString(); final String s = UrlBuilder.of(url, null).setCharset(CharsetUtil.CHARSET_UTF_8).toString();
@ -471,7 +471,7 @@ public class UrlBuilderTest {
@Test @Test
public void addPathTest() { public void addPathTest() {
//https://gitee.com/dromara/hutool/issues/I5O4ML //https://gitee.com/chinabugotech/hutool/issues/I5O4ML
UrlBuilder.of().addPath(""); UrlBuilder.of().addPath("");
UrlBuilder.of().addPath("/"); UrlBuilder.of().addPath("/");
UrlBuilder.of().addPath("//"); UrlBuilder.of().addPath("//");

View File

@ -22,7 +22,7 @@ public class UrlDecoderTest {
@Test @Test
public void issue3063Test() throws UnsupportedEncodingException { public void issue3063Test() throws UnsupportedEncodingException {
// https://github.com/dromara/hutool/issues/3063 // https://github.com/chinabugotech/hutool/issues/3063
final String s = "测试"; final String s = "测试";
final String expectedDecode = "%FE%FF%6D%4B%8B%D5"; final String expectedDecode = "%FE%FF%6D%4B%8B%D5";

View File

@ -52,7 +52,7 @@ public class UrlQueryTest {
@Test @Test
public void parseTest4(){ public void parseTest4(){
// https://github.com/dromara/hutool/issues/1989 // https://github.com/chinabugotech/hutool/issues/1989
String queryStr = "imageMogr2/thumbnail/x800/format/jpg"; String queryStr = "imageMogr2/thumbnail/x800/format/jpg";
final UrlQuery query = UrlQuery.of(queryStr, CharsetUtil.CHARSET_UTF_8); final UrlQuery query = UrlQuery.of(queryStr, CharsetUtil.CHARSET_UTF_8);
assertEquals(queryStr, query.toString()); assertEquals(queryStr, query.toString());

View File

@ -17,7 +17,7 @@ public class CharSequenceUtilTest {
@Test @Test
public void replaceTest2() { public void replaceTest2() {
// https://gitee.com/dromara/hutool/issues/I4M16G // https://gitee.com/chinabugotech/hutool/issues/I4M16G
String replace = "#{A}"; String replace = "#{A}";
String result = CharSequenceUtil.replace(replace, "#{AAAAAAA}", "1"); String result = CharSequenceUtil.replace(replace, "#{AAAAAAA}", "1");
assertEquals(replace, result); assertEquals(replace, result);
@ -49,7 +49,7 @@ public class CharSequenceUtilTest {
result = CharSequenceUtil.addSuffixIfNot(str, " is Good"); result = CharSequenceUtil.addSuffixIfNot(str, " is Good");
assertEquals(str + " is Good", result); assertEquals(str + " is Good", result);
// https://gitee.com/dromara/hutool/issues/I4NS0F // https://gitee.com/chinabugotech/hutool/issues/I4NS0F
result = CharSequenceUtil.addSuffixIfNot("", "/"); result = CharSequenceUtil.addSuffixIfNot("", "/");
assertEquals("/", result); assertEquals("/", result);
} }
@ -89,7 +89,7 @@ public class CharSequenceUtilTest {
@Test @Test
public void subPreGbkTest() { public void subPreGbkTest() {
// https://gitee.com/dromara/hutool/issues/I4JO2E // https://gitee.com/chinabugotech/hutool/issues/I4JO2E
String s = "华硕K42Intel酷睿i31代2G以下独立显卡不含机械硬盘固态硬盘120GB-192GB4GB-6GB"; String s = "华硕K42Intel酷睿i31代2G以下独立显卡不含机械硬盘固态硬盘120GB-192GB4GB-6GB";
String v = CharSequenceUtil.subPreGbk(s, 40, false); String v = CharSequenceUtil.subPreGbk(s, 40, false);
@ -101,7 +101,7 @@ public class CharSequenceUtilTest {
@Test @Test
public void startWithTest() { public void startWithTest() {
// https://gitee.com/dromara/hutool/issues/I4MV7Q // https://gitee.com/chinabugotech/hutool/issues/I4MV7Q
assertFalse(CharSequenceUtil.startWith("123", "123", false, true)); assertFalse(CharSequenceUtil.startWith("123", "123", false, true));
assertFalse(CharSequenceUtil.startWith(null, null, false, true)); assertFalse(CharSequenceUtil.startWith(null, null, false, true));
assertFalse(CharSequenceUtil.startWith("abc", "abc", true, true)); assertFalse(CharSequenceUtil.startWith("abc", "abc", true, true));

View File

@ -35,9 +35,9 @@ public class NamingCaseTest {
.set("H#case", "H#case") .set("H#case", "H#case")
.set("PNLabel", "PN_label") .set("PNLabel", "PN_label")
.set("wPRunOZTime", "w_P_run_OZ_time") .set("wPRunOZTime", "w_P_run_OZ_time")
// https://github.com/dromara/hutool/issues/2070 // https://github.com/chinabugotech/hutool/issues/2070
.set("customerNickV2", "customer_nick_v2") .set("customerNickV2", "customer_nick_v2")
// https://gitee.com/dromara/hutool/issues/I4X9TT // https://gitee.com/chinabugotech/hutool/issues/I4X9TT
.set("DEPT_NAME","DEPT_NAME") .set("DEPT_NAME","DEPT_NAME")
.forEach((key, value) -> assertEquals(value, NamingCase.toUnderlineCase(key))); .forEach((key, value) -> assertEquals(value, NamingCase.toUnderlineCase(key)));
} }

View File

@ -9,7 +9,7 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* https://gitee.com/dromara/hutool/issues/IA8WE0 * https://gitee.com/chinabugotech/hutool/issues/IA8WE0
*/ */
public class IssueIA8WE0Test { public class IssueIA8WE0Test {
@Test @Test

View File

@ -74,7 +74,7 @@ public class StrSplitterTest {
} }
/** /**
* https://github.com/dromara/hutool/issues/2099 * https://github.com/chinabugotech/hutool/issues/2099
*/ */
@Test @Test
public void splitByRegexTest(){ public void splitByRegexTest(){

View File

@ -11,7 +11,7 @@ public class ExecutorBuilderTest {
@Test @Test
@Disabled @Disabled
public void CallerRunsPolicyTest(){ public void CallerRunsPolicyTest(){
// https://gitee.com/dromara/hutool/pulls/660 // https://gitee.com/chinabugotech/hutool/pulls/660
final ThreadPoolExecutor executor = ExecutorBuilder.create().setCorePoolSize(1).setMaxPoolSize(1).setHandler(RejectPolicy.BLOCK.getValue()).build(); final ThreadPoolExecutor executor = ExecutorBuilder.create().setCorePoolSize(1).setMaxPoolSize(1).setHandler(RejectPolicy.BLOCK.getValue()).build();
executor.execute(()-> Console.log("### 1")); executor.execute(()-> Console.log("### 1"));
executor.execute(()-> Console.log("### 2")); executor.execute(()-> Console.log("### 2"));

View File

@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class SyncFinisherTest { public class SyncFinisherTest {
/** /**
* https://gitee.com/dromara/hutool/issues/I716SX * https://gitee.com/chinabugotech/hutool/issues/I716SX
* 设置ExceptionHandler捕获异常 * 设置ExceptionHandler捕获异常
*/ */
@Test @Test
@ -44,7 +44,7 @@ public class SyncFinisherTest {
} }
/** /**
* https://gitee.com/dromara/hutool/issues/I716SX * https://gitee.com/chinabugotech/hutool/issues/I716SX
* 默认情况下吞掉异常 * 默认情况下吞掉异常
*/ */
@Test @Test

View File

@ -39,7 +39,7 @@ public class EscapeUtilTest {
} }
/** /**
* https://gitee.com/dromara/hutool/issues/I49JU8 * https://gitee.com/chinabugotech/hutool/issues/I49JU8
*/ */
@Test @Test
public void escapeAllTest2(){ public void escapeAllTest2(){

View File

@ -45,7 +45,7 @@ public class HexUtilTest {
String a = "0x3544534F444"; String a = "0x3544534F444";
assertTrue(HexUtil.isHexNumber(a)); assertTrue(HexUtil.isHexNumber(a));
// https://gitee.com/dromara/hutool/issues/I62H7K // https://gitee.com/chinabugotech/hutool/issues/I62H7K
a = "0x0000000000000001158e460913d00000"; a = "0x0000000000000001158e460913d00000";
assertTrue(HexUtil.isHexNumber(a)); assertTrue(HexUtil.isHexNumber(a));
@ -53,7 +53,7 @@ public class HexUtilTest {
a = "0x0000001000T00001158e460913d00000"; a = "0x0000001000T00001158e460913d00000";
assertFalse(HexUtil.isHexNumber(a)); assertFalse(HexUtil.isHexNumber(a));
// 错误的,https://github.com/dromara/hutool/issues/2857 // 错误的,https://github.com/chinabugotech/hutool/issues/2857
a = "-1"; a = "-1";
assertFalse(HexUtil.isHexNumber(a)); assertFalse(HexUtil.isHexNumber(a));
} }

View File

@ -20,7 +20,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* https://github.com/dromara/hutool/issues/3136 * https://github.com/chinabugotech/hutool/issues/3136
*/ */
public class Issue3136Test { public class Issue3136Test {

View File

@ -0,0 +1,13 @@
package cn.hutool.core.util;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class IssueIBP6T1Test {
@SuppressWarnings("DataFlowIssue")
@Test
void isValidCard10Test(){
Assertions.assertEquals("true", IdcardUtil.isValidCard10("1608214(1)")[2]);
Assertions.assertEquals("true", IdcardUtil.isValidCard10("16082141")[2]);
}
}

View File

@ -416,7 +416,7 @@ public class StrUtilTest {
containsAny = StrUtil.containsAny("aaabbbccc", "d", "c"); containsAny = StrUtil.containsAny("aaabbbccc", "d", "c");
assertTrue(containsAny); assertTrue(containsAny);
// https://gitee.com/dromara/hutool/issues/I7WSYD // https://gitee.com/chinabugotech/hutool/issues/I7WSYD
containsAny = StrUtil.containsAny("你好啊", "", null); containsAny = StrUtil.containsAny("你好啊", "", null);
assertFalse(containsAny); assertFalse(containsAny);
} }
@ -651,7 +651,7 @@ public class StrUtilTest {
@Test @Test
public void issueI6KKFUTest() { public void issueI6KKFUTest() {
// https://gitee.com/dromara/hutool/issues/I6KKFU // https://gitee.com/chinabugotech/hutool/issues/I6KKFU
final String template = "I''m {0} years old."; final String template = "I''m {0} years old.";
final String result = StrUtil.indexedFormat(template, 10); final String result = StrUtil.indexedFormat(template, 10);
assertEquals("I'm 10 years old.", result); assertEquals("I'm 10 years old.", result);

View File

@ -4,8 +4,12 @@ import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import cn.hutool.core.lang.TypeReference;
import lombok.Data; import lombok.Data;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class TypeUtilTest { public class TypeUtilTest {
@ -97,4 +101,29 @@ public class TypeUtilTest {
private T level; private T level;
} }
/**
* fix github:issue#3873
*/
@Test
public void getActualTypeForGenericArrayTest() {
TypeReference<GenericArray<GenericArrayEle>> typeReference = new TypeReference<GenericArray<GenericArrayEle>>() {
};
Type levelType = TypeUtil.getFieldType(GenericArray.class, "level");
Type actualType = TypeUtil.getActualType(typeReference.getType(), levelType);
assertEquals(ArrayUtil.getArrayType(GenericArrayEle.class), actualType);
}
@Data
public static class GenericArray<T> {
private T[] level;
}
@Data
public static class GenericArrayEle {
private Long uid;
}
} }

View File

@ -0,0 +1,79 @@
package cn.hutool.core.util;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.exceptions.UtilException;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class VersionUtilTest {
@Test
void isGreaterThan() {
String currentVersion = " 1.0.2";
assertTrue(VersionUtil.isGreaterThan(currentVersion, "1.0.1"));
assertTrue(VersionUtil.isGreaterThan(currentVersion, "1"));
assertFalse(VersionUtil.isGreaterThan(currentVersion, "1.1"));
}
@Test
void isGreaterThanOrEqual() {
String currentVersion = "1.0.2 ";
assertTrue(VersionUtil.isGreaterThanOrEqual(currentVersion, "1.0.1"));
assertTrue(VersionUtil.isGreaterThanOrEqual(currentVersion, "1.0.2"));
assertFalse(VersionUtil.isGreaterThanOrEqual(currentVersion, "1.1"));
}
@Test
void isLessThan() {
String currentVersion = "1.0.2";
assertTrue(VersionUtil.isLessThan(currentVersion, "1.0.3"));
assertFalse(VersionUtil.isLessThan(currentVersion, "1"));
assertTrue(VersionUtil.isLessThan(currentVersion, "1.1"));
assertFalse(VersionUtil.isLessThan(currentVersion, "1.0.2"));
}
@Test
void isLessThanOrEqual() {
String currentVersion = "1.0.2";
assertTrue(VersionUtil.isLessThanOrEqual(currentVersion, "1.0.2"));
assertFalse(VersionUtil.isLessThanOrEqual(currentVersion, "1.0.1"));
assertTrue(VersionUtil.isLessThanOrEqual(currentVersion, "1.1"));
}
@Test
void matchEl() {
String currentVersion = "1.0.2";
assertTrue(VersionUtil.matchEl(currentVersion, "1.0.1;1.0.2"));
assertFalse(VersionUtil.matchEl(currentVersion, "1.0.1;1.0.3"));
assertTrue(VersionUtil.matchEl(currentVersion, "1.0.9;1.0.1-1.0.2"));
assertTrue(VersionUtil.matchEl(currentVersion, "1.0.9;1.0.1-1.0.3"));
assertTrue(VersionUtil.matchEl(currentVersion, "1.0.9,1.0.1-1.0.3", ","));
}
@Test
void matchEl_Exception_whenVersionDelimiterIllegal() {
List<String> illegalDelimiters = ListUtil.of("-", ">", ">=", "<", "<=", "", "", null, "", " ");
for (String illegalDelimiter : illegalDelimiters) {
assertThrows(UtilException.class, () -> {
String currentVersion = "1.0.2";
VersionUtil.matchEl(currentVersion, "1.0.1;1.0.2", illegalDelimiter);
});
}
}
@Test
void anyMatch() {
String currentVersion = "1.0.2";
assertTrue(VersionUtil.anyMatch(currentVersion, ListUtil.of("1.0.1", "1.0.3", "1.0.2")));
assertTrue(VersionUtil.anyMatch(currentVersion, "1.0.1", "1.0.2"));
}
@Test
void testMatchEl() {
}
}

View File

@ -149,7 +149,7 @@ public class ZipUtilTest {
@Test @Test
@Disabled @Disabled
public void zipStreamTest(){ public void zipStreamTest(){
//https://github.com/dromara/hutool/issues/944 //https://github.com/chinabugotech/hutool/issues/944
final String dir = "d:/test"; final String dir = "d:/test";
final String zip = "d:/test.zip"; final String zip = "d:/test.zip";
//noinspection IOStreamConstructor //noinspection IOStreamConstructor
@ -164,7 +164,7 @@ public class ZipUtilTest {
@Test @Test
@Disabled @Disabled
public void zipStreamTest2(){ public void zipStreamTest2(){
// https://github.com/dromara/hutool/issues/944 // https://github.com/chinabugotech/hutool/issues/944
final String file1 = "d:/test/a.txt"; final String file1 = "d:/test/a.txt";
final String file2 = "d:/test/a.txt"; final String file2 = "d:/test/a.txt";
final String file3 = "d:/test/asn1.key"; final String file3 = "d:/test/asn1.key";

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-cron</artifactId> <artifactId>hutool-cron</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-crypto</artifactId> <artifactId>hutool-crypto</artifactId>

View File

@ -61,7 +61,7 @@ public class KeyUtilTest {
@Test @Test
public void generateSm4KeyTest(){ public void generateSm4KeyTest(){
// https://github.com/dromara/hutool/issues/2150 // https://github.com/chinabugotech/hutool/issues/2150
assertEquals(16, KeyUtil.generateKey("sm4").getEncoded().length); assertEquals(16, KeyUtil.generateKey("sm4").getEncoded().length);
assertEquals(32, KeyUtil.generateKey("sm4", 256).getEncoded().length); assertEquals(32, KeyUtil.generateKey("sm4", 256).getEncoded().length);
} }

View File

@ -64,7 +64,7 @@ public class PemUtilTest {
@Test @Test
@Disabled @Disabled
public void readECPrivateKeyTest2() { public void readECPrivateKeyTest2() {
// https://gitee.com/dromara/hutool/issues/I37Z75 // https://gitee.com/chinabugotech/hutool/issues/I37Z75
final byte[] d = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/priv.key")); final byte[] d = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/priv.key"));
final byte[] publicKey = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/pub.key")); final byte[] publicKey = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/pub.key"));

View File

@ -6,14 +6,15 @@ import cn.hutool.crypto.digest.mac.SM4MacEngine;
import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.params.ParametersWithIV;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CBCBlockCipherMacEngineTest { public class CBCBlockCipherMacEngineTest {
@Test @Test
public void SM4CMACTest(){ public void SM4CMACTest(){
// https://github.com/dromara/hutool/issues/2206 // https://github.com/chinabugotech/hutool/issues/2206
final byte[] key = new byte[16]; final byte[] key = new byte[16];
final CipherParameters parameter = new KeyParameter(KeyUtil.generateKey("SM4", key).getEncoded()); final CipherParameters parameter = new KeyParameter(KeyUtil.generateKey("SM4", key).getEncoded());
Mac mac = new Mac(new SM4MacEngine(parameter)); Mac mac = new Mac(new SM4MacEngine(parameter));
@ -27,7 +28,7 @@ public class CBCBlockCipherMacEngineTest {
@Test @Test
public void SM4CMACWithIVTest(){ public void SM4CMACWithIVTest(){
// https://github.com/dromara/hutool/issues/2206 // https://github.com/chinabugotech/hutool/issues/2206
final byte[] key = new byte[16]; final byte[] key = new byte[16];
final byte[] iv = new byte[16]; final byte[] iv = new byte[16];
CipherParameters parameter = new KeyParameter(KeyUtil.generateKey("SM4", key).getEncoded()); CipherParameters parameter = new KeyParameter(KeyUtil.generateKey("SM4", key).getEncoded());

View File

@ -5,11 +5,12 @@ import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.KeyUtil; import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.ZUC; import cn.hutool.crypto.symmetric.ZUC;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* Hmac单元测试 * Hmac单元测试
* @author Looly * @author Looly
@ -84,7 +85,7 @@ public class HmacTest {
@Test @Test
public void sm4CMACTest(){ public void sm4CMACTest(){
// https://github.com/dromara/hutool/issues/2206 // https://github.com/chinabugotech/hutool/issues/2206
final byte[] key = new byte[16]; final byte[] key = new byte[16];
HMac mac = new HMac(HmacAlgorithm.SM4CMAC, HMac mac = new HMac(HmacAlgorithm.SM4CMAC,
KeyUtil.generateKey("SM4", key)); KeyUtil.generateKey("SM4", key));

View File

@ -10,7 +10,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* https://gitee.com/dromara/hutool/issues/I4EMST * https://gitee.com/chinabugotech/hutool/issues/I4EMST
*/ */
public class Sm4StreamTest { public class Sm4StreamTest {

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-db</artifactId> <artifactId>hutool-db</artifactId>

View File

@ -148,7 +148,7 @@ public interface Dialect extends Serializable {
* @since 5.7.2 * @since 5.7.2
*/ */
default PreparedStatement psForCount(Connection conn, SqlBuilder sqlBuilder) throws SQLException { default PreparedStatement psForCount(Connection conn, SqlBuilder sqlBuilder) throws SQLException {
// https://gitee.com/dromara/hutool/issues/I713XQ // https://gitee.com/chinabugotech/hutool/issues/I713XQ
// 为了兼容informix等数据库此处使用count(*)而非count(1) // 为了兼容informix等数据库此处使用count(*)而非count(1)
sqlBuilder = sqlBuilder sqlBuilder = sqlBuilder
.insertPreFragment("SELECT count(*) from(") .insertPreFragment("SELECT count(*) from(")

View File

@ -45,7 +45,8 @@ public class DialectFactory implements DriverNamePool {
*/ */
private static Dialect internalNewDialect(String driverName) { private static Dialect internalNewDialect(String driverName) {
if (StrUtil.isNotBlank(driverName)) { if (StrUtil.isNotBlank(driverName)) {
if (DRIVER_MYSQL.equalsIgnoreCase(driverName) || DRIVER_MYSQL_V6.equalsIgnoreCase(driverName)) { if (DRIVER_MYSQL.equalsIgnoreCase(driverName) || DRIVER_MYSQL_V6.equalsIgnoreCase(driverName)
|| DRIVER_GOLDENDB.equalsIgnoreCase(driverName)) {
return new MysqlDialect(); return new MysqlDialect();
} else if (DRIVER_ORACLE.equalsIgnoreCase(driverName) || DRIVER_ORACLE_OLD.equalsIgnoreCase(driverName)) { } else if (DRIVER_ORACLE.equalsIgnoreCase(driverName) || DRIVER_ORACLE_OLD.equalsIgnoreCase(driverName)) {
return new OracleDialect(); return new OracleDialect();
@ -164,6 +165,9 @@ public class DialectFactory implements DriverNamePool {
} else if (nameContainsProductInfo.contains("opengauss")) { } else if (nameContainsProductInfo.contains("opengauss")) {
// OpenGauss // OpenGauss
driver = DRIVER_OPENGAUSS; driver = DRIVER_OPENGAUSS;
} else if (nameContainsProductInfo.contains("goldendb")) {
// GoldenDB
driver = DRIVER_GOLDENDB;
} }
return driver; return driver;

View File

@ -116,4 +116,8 @@ public interface DriverNamePool {
* JDBC 驱动 OpenGauss * JDBC 驱动 OpenGauss
*/ */
String DRIVER_OPENGAUSS = "org.opengauss.Driver"; String DRIVER_OPENGAUSS = "org.opengauss.Driver";
/**
* JDBC 驱动 GoldenDB
*/
String DRIVER_GOLDENDB = "com.goldendb.jdbc.Driver";
} }

View File

@ -122,7 +122,7 @@ public class DbTest {
@Test @Test
@Disabled @Disabled
public void queryFetchTest() throws SQLException { public void queryFetchTest() throws SQLException {
// https://gitee.com/dromara/hutool/issues/I4JXWN // https://gitee.com/chinabugotech/hutool/issues/I4JXWN
Db.use().query((conn->{ Db.use().query((conn->{
PreparedStatement ps = conn.prepareStatement("select * from table", PreparedStatement ps = conn.prepareStatement("select * from table",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_FORWARD_ONLY,

View File

@ -91,7 +91,7 @@ public class DsTest {
@Test @Test
public void c3p0DsUserAndPassTest() { public void c3p0DsUserAndPassTest() {
// https://gitee.com/dromara/hutool/issues/I4T7XZ // https://gitee.com/chinabugotech/hutool/issues/I4T7XZ
DSFactory.setCurrentDSFactory(new C3p0DSFactory()); DSFactory.setCurrentDSFactory(new C3p0DSFactory());
ComboPooledDataSource ds = (ComboPooledDataSource) ((DataSourceWrapper) DSFactory.get("mysql")).getRaw(); ComboPooledDataSource ds = (ComboPooledDataSource) ((DataSourceWrapper) DSFactory.get("mysql")).getRaw();
assertEquals("root", ds.getUser()); assertEquals("root", ds.getUser());

View File

@ -0,0 +1,10 @@
package cn.hutool.db;
import org.junit.jupiter.api.Test;
public class GlobalDbConfigTest {
@Test
void createDbSettingTest(){
GlobalDbConfig.createDbSetting();
}
}

View File

@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test;
import java.sql.SQLException; import java.sql.SQLException;
/** /**
* https://gitee.com/dromara/hutool/issues/I73770 * https://gitee.com/chinabugotech/hutool/issues/I73770
*/ */
public class IssueI73770Test { public class IssueI73770Test {
@Test @Test

View File

@ -42,6 +42,7 @@ public class DialectFactoryTest {
map.put("oscar",DRIVER_OSCAR); map.put("oscar",DRIVER_OSCAR);
map.put("sybase",DRIVER_SYBASE); map.put("sybase",DRIVER_SYBASE);
map.put("mariadb",DRIVER_MARIADB); map.put("mariadb",DRIVER_MARIADB);
map.put("goldendb",DRIVER_GOLDENDB);
map.forEach((k,v) -> assertEquals(v, map.forEach((k,v) -> assertEquals(v,

View File

@ -51,4 +51,4 @@ idleConnectionTestPeriod = 0
# c3p0全局的PreparedStatements缓存的大小。如果maxStatements与maxStatementsPerConnection均为0则缓存不生效只要有一个不为0则语句的缓存就能生效。如果默认值: 0 # c3p0全局的PreparedStatements缓存的大小。如果maxStatements与maxStatementsPerConnection均为0则缓存不生效只要有一个不为0则语句的缓存就能生效。如果默认值: 0
maxStatements = 0 maxStatements = 0
# maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。默认值: 0 # maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。默认值: 0
maxStatementsPerConnection = 0 maxStatementsPerConnection = 0

View File

@ -48,4 +48,4 @@ testOnBorrow = false
# (boolean) 指明是否在归还到池中前进行检验 注意: 设置为true 后如果要生效validationQuery 参数必须设置为非空字符串 # (boolean) 指明是否在归还到池中前进行检验 注意: 设置为true 后如果要生效validationQuery 参数必须设置为非空字符串
testOnReturn = false testOnReturn = false
# (boolean) 指明连接是否被空闲连接回收器( 如果有) 进行检验。 如果检测失败, 则连接将被从池中去除。注意: 设置为true 后如果要生效validationQuery 参数必须设置为非空字符串 # (boolean) 指明连接是否被空闲连接回收器( 如果有) 进行检验。 如果检测失败, 则连接将被从池中去除。注意: 设置为true 后如果要生效validationQuery 参数必须设置为非空字符串
testWhileIdle = false testWhileIdle = false

View File

@ -52,4 +52,4 @@ connectionInitSqls = SELECT 1
# 属性类型是字符串,通过别名的方式配置扩展插件, 常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall # 属性类型是字符串,通过别名的方式配置扩展插件, 常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
filters = stat filters = stat
# 类型是List<com.alibaba.druid.filter.Filter> 如果同时配置了filters和proxyFilters 是组合关系,并非替换关系 # 类型是List<com.alibaba.druid.filter.Filter> 如果同时配置了filters和proxyFilters 是组合关系,并非替换关系
proxyFilters = proxyFilters =

View File

@ -40,4 +40,4 @@ minimumIdle = 10
# 连接池中允许的最大连接数。缺省值10推荐的公式((core_count * 2) + effective_spindle_count) # 连接池中允许的最大连接数。缺省值10推荐的公式((core_count * 2) + effective_spindle_count)
maximumPoolSize = 10 maximumPoolSize = 10
# 连接只读数据库时配置为true 保证安全 # 连接只读数据库时配置为true 保证安全
readOnly = false readOnly = false

View File

@ -48,4 +48,4 @@ testOnBorrow = false
# (boolean) 指明是否在归还到池中前进行检验 注意: 设置为true 后如果要生效validationQuery 参数必须设置为非空字符串 # (boolean) 指明是否在归还到池中前进行检验 注意: 设置为true 后如果要生效validationQuery 参数必须设置为非空字符串
testOnReturn = false testOnReturn = false
# (boolean) 指明连接是否被空闲连接回收器( 如果有) 进行检验。 如果检测失败, 则连接将被从池中去除。注意: 设置为true 后如果要生效validationQuery 参数必须设置为非空字符串 # (boolean) 指明连接是否被空闲连接回收器( 如果有) 进行检验。 如果检测失败, 则连接将被从池中去除。注意: 设置为true 后如果要生效validationQuery 参数必须设置为非空字符串
testWhileIdle = false testWhileIdle = false

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.8.36</version> <version>5.8.37-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-dfa</artifactId> <artifactId>hutool-dfa</artifactId>

Some files were not shown because too many files have changed in this diff Show More