Compare commits

...

8 Commits

Author SHA1 Message Date
Looly
a32fac8760 add test 2026-01-17 19:57:28 +08:00
Golden Looly
266cd0754c Merge pull request #4215 from Kang-Yang/v5-dev
修复:更新SSLUtil注释内容
2026-01-17 19:44:37 +08:00
Kang-Yang
6fe9f31eaf 修复:更新SSLUtil注释内容 2026-01-17 19:25:35 +08:00
Looly
fa79eee1ce AbstractCaptcha增加setStroke方法支持线条粗细(issue#IDJQ15@Gitee) 2026-01-14 11:51:56 +08:00
Looly
12547f4d4c NumberUtil.parseNumber增加支持科学计数法(pr#4211@Github) 2026-01-12 16:08:17 +08:00
Golden Looly
af48fa825c Merge pull request #4211 from Shinomiya-s/fix-numberutil-parse-scientific
fix: correct NumberUtil.parseNumber scientific notation parsing
2026-01-12 16:01:37 +08:00
Shinomiya-s
c12b87f8b7 fix: correct NumberUtil.parseNumber scientific notation parsing, add parseNumberTest5 2026-01-12 14:14:09 +08:00
Looly
915f7c429b 修复JSONUtil.wrap忽略错误问题(issue#4210@Github) 2026-01-12 09:47:23 +08:00
11 changed files with 129 additions and 9 deletions

View File

@@ -1,10 +1,13 @@
# 🚀Changelog # 🚀Changelog
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.8.44 # 5.8.44(2026-01-12)
### 🐣新特性 ### 🐣新特性
* 【core 】 `NumberUtil.parseNumber`增加支持科学计数法pr#4211@Github
* 【captcha】 `AbstractCaptcha`增加`setStroke`方法支持线条粗细issue#IDJQ15@Gitee
### 🐞Bug修复 ### 🐞Bug修复
* 【json 】 修复`JSONUtil.wrap`忽略错误问题issue#4210@Github
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.8.43(2026-01-04) # 5.8.43(2026-01-04)

View File

@@ -9,10 +9,7 @@ import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.URLUtil; import cn.hutool.core.util.URLUtil;
import java.awt.AlphaComposite; import java.awt.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@@ -65,6 +62,7 @@ public abstract class AbstractCaptcha implements ICaptcha {
* 文字透明度 * 文字透明度
*/ */
protected AlphaComposite textAlpha; protected AlphaComposite textAlpha;
protected Stroke stroke;
/** /**
* 构造,使用随机验证码生成器生成验证码 * 构造,使用随机验证码生成器生成验证码
@@ -271,4 +269,13 @@ public abstract class AbstractCaptcha implements ICaptcha {
this.textAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, textAlpha); this.textAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, textAlpha);
} }
/**
* 设置画笔线条特征,如线条宽度等
*
* @param stroke 画笔
* @since 5.8.44
*/
public void setStroke(Stroke stroke) {
this.stroke = stroke;
}
} }

View File

@@ -118,6 +118,11 @@ public class CircleCaptcha extends AbstractCaptcha {
* @param g {@link Graphics2D} * @param g {@link Graphics2D}
*/ */
private void drawInterfere(Graphics2D g) { private void drawInterfere(Graphics2D g) {
// issue#IDJQ15 自定义线条特征(粗细等)
if(null != this.stroke){
g.setStroke(this.stroke);
}
final ThreadLocalRandom random = RandomUtil.getRandom(); final ThreadLocalRandom random = RandomUtil.getRandom();
for (int i = 0; i < this.interfereCount; i++) { for (int i = 0; i < this.interfereCount; i++) {

View File

@@ -110,6 +110,11 @@ public class LineCaptcha extends AbstractCaptcha {
* @param g {@link Graphics2D}画笔 * @param g {@link Graphics2D}画笔
*/ */
private void drawInterfere(Graphics2D g) { private void drawInterfere(Graphics2D g) {
// issue#IDJQ15 自定义线条特征(粗细等)
if(null != this.stroke){
g.setStroke(this.stroke);
}
final ThreadLocalRandom random = RandomUtil.getRandom(); final ThreadLocalRandom random = RandomUtil.getRandom();
// 干扰线 // 干扰线
for (int i = 0; i < this.interfereCount; i++) { for (int i = 0; i < this.interfereCount; i++) {

View File

@@ -193,7 +193,6 @@ public class ShearCaptcha extends AbstractCaptcha {
*/ */
@SuppressWarnings("SameParameterValue") @SuppressWarnings("SameParameterValue")
private void drawInterfere(Graphics g, int x1, int y1, int x2, int y2, int thickness, Color c) { private void drawInterfere(Graphics g, int x1, int y1, int x2, int y2, int thickness, Color c) {
// The thick line is in fact a filled polygon // The thick line is in fact a filled polygon
g.setColor(c); g.setColor(c);
int dX = x2 - x1; int dX = x2 - x1;

View File

@@ -15,7 +15,7 @@ import javax.net.ssl.TrustManager;
public class SSLUtil { public class SSLUtil {
/** /**
* 创建{@link SSLContext},默认新人全部 * 创建{@link SSLContext},默认信任全部
* *
* @param protocol SSL协议例如TLS等 * @param protocol SSL协议例如TLS等
* @return {@link SSLContext} * @return {@link SSLContext}

View File

@@ -2783,6 +2783,16 @@ public class NumberUtil {
// issue@4197@Github 转为半角 // issue@4197@Github 转为半角
numberStr = Convert.toDBC(numberStr); numberStr = Convert.toDBC(numberStr);
// issue#IDJ1NS@Gitee 处理科学计数法E+格式
// NumberFormat对E+格式支持不佳,使用BigDecimal直接解析
if (StrUtil.containsIgnoreCase(numberStr, "e")) {
try {
return new BigDecimal(numberStr);
} catch (NumberFormatException e) {
// BigDecimal解析失败,继续使用NumberFormat尝试
}
}
try { try {
final NumberFormat format = NumberFormat.getInstance(); final NumberFormat format = NumberFormat.getInstance();
if (format instanceof DecimalFormat) { if (format instanceof DecimalFormat) {

View File

@@ -388,6 +388,16 @@ public class NumberUtilTest {
} }
@Test
void issueIDJ1NSTest(){
final String numberstr1 = "8.37095942E+9";
final BigDecimal result1 = (BigDecimal) NumberUtil.parseNumber(numberstr1);
final String numberstr2 = "8.37095942e+9";
final BigDecimal result2 = (BigDecimal) NumberUtil.parseNumber(numberstr2);
assertEquals(new BigDecimal("8370959420").toPlainString(), result1.toPlainString());
assertEquals(new BigDecimal("8370959420").toPlainString(), result2.toPlainString());
}
@Test @Test
public void parseHexNumberTest() { public void parseHexNumberTest() {
// 千位分隔符去掉 // 千位分隔符去掉

View File

@@ -739,7 +739,7 @@ public class JSONUtil {
* <li>map =》 JSONObject</li> * <li>map =》 JSONObject</li>
* <li>standard property (Double, String, et al) =》 原对象</li> * <li>standard property (Double, String, et al) =》 原对象</li>
* <li>来自于java包 =》 字符串</li> * <li>来自于java包 =》 字符串</li>
* <li>其它 =》 尝试包装为JSONObject否则返回{@code null}</li> * <li>其它 =》 尝试包装为JSONObject如果{@link JSONConfig#isIgnoreError()}为true时返回{@code null}, 否则抛出异常</li>
* </ul> * </ul>
* *
* @param object 被包装的对象 * @param object 被包装的对象
@@ -805,7 +805,11 @@ public class JSONUtil {
// 默认按照JSONObject对待 // 默认按照JSONObject对待
return new JSONObject(object, jsonConfig); return new JSONObject(object, jsonConfig);
} catch (final Exception exception) { } catch (final Exception exception) {
return null; // issue#4210 只有设置忽略错误时才返回null
if(jsonConfig.isIgnoreError()){
return null;
}
throw exception;
} }
} }

View File

@@ -0,0 +1,45 @@
package cn.hutool.json;
import cn.hutool.core.exceptions.InvocationTargetRuntimeException;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.ObjectId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.Serializable;
public class Issue4210Test {
@Test
void setValueTest(){
final JSONObject jsonObject = new JSONObject();
final TestEntity entity = new TestEntity("张三", "社畜");
Assertions.assertThrows(InvocationTargetRuntimeException.class, () -> jsonObject.set("entity",entity));
}
@Data
public static class BaseEntity implements Serializable {
/**
* 实体唯一标识符
*/
private String _id;
private ObjectId id;
public String get_id() {
return _id == null ? id.toString() : _id;
}
}
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public class TestEntity extends BaseEntity{
private String name;
private String desc;
}
}

View File

@@ -0,0 +1,32 @@
package cn.hutool.json;
import lombok.Data;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class Issue4214Test {
@Test
void toBeanTest(){
LicenseInfo licenseInfo = new LicenseInfo();
licenseInfo.setAuthTypeEnum(AuthTypeEnum.OFFICIAL);
String jsonStr = JSONUtil.toJsonStr(licenseInfo);
assertEquals("{\"authTypeEnum\":\"OFFICIAL\"}", jsonStr);
// 这里反序列化会报错
LicenseInfo bean = JSONUtil.toBean(jsonStr, LicenseInfo.class);
assertEquals(AuthTypeEnum.OFFICIAL, bean.getAuthTypeEnum());
}
@Data
static class LicenseInfo{
private AuthTypeEnum authTypeEnum;
}
enum AuthTypeEnum{
OFFICIAL,
SELF_BUILD
}
}