Compare commits

...

12 Commits

Author SHA1 Message Date
Looly
5ae493119f fix doc 2025-11-26 20:05:44 +08:00
Looly
ea717843f6 fix doc 2025-11-26 20:04:48 +08:00
Looly
b8908cf3ef 增强HexUtil自动去除0x#前缀(pr#4163@Github) 2025-11-26 20:02:12 +08:00
Golden Looly
ab1774d4e6
Merge pull request #4163 from sunshineflymeat/hutool-1126-3
Fix issue 4162
2025-11-26 19:57:15 +08:00
Looly
ccaecf6bc9 Word07Writer增加addText重载,支持字体颜色(pr#1388@Gitee) 2025-11-26 19:44:34 +08:00
Looly
3d2dd38add
!1388 feat:Word生成器,增加段落新增字体颜色参数
Merge pull request !1388 from liyong473/v5-dev
2025-11-26 11:41:26 +00:00
Looly
d64a0d36aa 修复DateModifier处理AM和PM的ceiling和round问题(pr#4161@Github) 2025-11-26 17:24:16 +08:00
Golden Looly
ab936327a2
Merge pull request #4161 from asukavuuyn/v5-dev
fix:12小时制ceiling和round问题
2025-11-26 17:22:07 +08:00
liyong
6ef5f1c1fd feat:Word生成器,增加段落新增字体颜色参数 2025-11-26 17:16:51 +08:00
ZWM
6776ddb29d Fix issue 4162 2025-11-26 17:11:18 +08:00
Looly
449df10509 修复ReflectUtil.newInstanceIfPossible传入Object逻辑错误(pr#4160@Github) 2025-11-26 16:30:34 +08:00
asukavuuyn
fc5e1ecff9 fix:12小时制ceiling和round问题 2025-11-26 15:19:41 +08:00
10 changed files with 200 additions and 39 deletions

View File

@ -11,6 +11,8 @@
* 【core 】 `Combination``Arrangement `重构避免数组频繁拷贝并避免溢出pr#4144@Github
* 【core 】 优化`EscapeUtil`兼容不规范的转义pr#4150@Github
* 【core 】 优化`ObjectUtil.contains`String改为CharSequencepr#4154@Github
* 【poi 】 `Word07Writer`增加addText重载支持字体颜色pr#1388@Gitee
* 【core 】 增强`HexUtil`自动去除`0x``#`前缀pr#4163@Github
### 🐞Bug修复
* 【jwt 】 修复verify方法在定义alg为`none`时验证失效问题issue#4105@Github
@ -31,6 +33,8 @@
* 【core 】 修复`URLUtil.url`未断开连接问题pr#4149@Github
* 【core 】 修复`Bimap.put`重复put问题pr#4150@Github
* 【core 】 修复`StrUtil.str(ByteBuffer, Charset)` 方法修改入参 `ByteBuffer``position`,导致入参变化 pr#4153@Github
* 【core 】 修复`ReflectUtil.newInstanceIfPossible`传入Object逻辑错误pr#4160@Github
* 【core 】 修复`DateModifier`处理AM和PM的ceiling和round问题pr#4161@Github
-------------------------------------------------------------------------------------------------------------
# 5.8.41(2025-10-12)

View File

@ -73,13 +73,13 @@ public class DateModifier {
case ROUND:
int min = isAM ? 0 : 12;
int max = isAM ? 11 : 23;
int href = (max - min) / 2 + 1;
int href = min + (max - min) / 2 + 1;
int value = calendar.get(Calendar.HOUR_OF_DAY);
calendar.set(Calendar.HOUR_OF_DAY, (value < href) ? min : max);
break;
}
// 处理下一级别字段
return modify(calendar, dateField + 1, modifyType);
return modify(calendar, dateField + 1, modifyType, truncateMillisecond);
}
final int endField = truncateMillisecond ? Calendar.SECOND : Calendar.MILLISECOND;

View File

@ -57,9 +57,9 @@ public class Combination implements Serializable {
* 1. 利用对称性 m = min(m, n-m)
* 2. 每一步先乘 BigInteger再除以当前 i保证数值不暴涨
*
* @param n 总数 n必须 >= 0
* @param m 取出 m必须 >= 0
* @return C(n, m) BigInteger 精确值 m > n 时返回 BigInteger.ZERO
* @param n 总数 n必须 大于等于 0
* @param m 取出 m必须 大于等于 0
* @return C(n, m) BigInteger 精确值 m 大于 n 时返回 BigInteger.ZERO
*/
public static BigInteger countBig(int n, int m) {
if (n < 0 || m < 0) {
@ -87,9 +87,10 @@ public class Combination implements Serializable {
/**
* 安全组合数 long 版本
*
* @param n 总数 n必须 >= 0
* @param m 取出 m必须 >= 0
* @param n 总数 n必须 大于等于 0
* @param m 取出 m必须 大于等于 0
* <p>若结果超出 long 范围会抛 ArithmeticException而非溢出</p>
* @return C(n, m) long 精确值 m 大于 n 时返回 0L
*/
public static long countSafe(int n, int m) {
BigInteger big = countBig(n, m);

View File

@ -304,7 +304,7 @@ public class HexUtil {
* @since 5.7.4
*/
public static int hexToInt(String value) {
return Integer.parseInt(value, 16);
return Integer.parseInt(removeHexPrefix(value), 16);
}
/**
@ -326,7 +326,7 @@ public class HexUtil {
* @since 5.7.4
*/
public static long hexToLong(String value) {
return Long.parseLong(value, 16);
return Long.parseLong(removeHexPrefix(value), 16);
}
/**
@ -352,7 +352,7 @@ public class HexUtil {
if (null == hexStr) {
return null;
}
return new BigInteger(hexStr, 16);
return new BigInteger(removeHexPrefix(hexStr), 16);
}
/**
@ -392,4 +392,24 @@ public class HexUtil {
return builder.toString();
}
/**
* 去除十六进制字符串的常见前缀 0x0X#
*
* @param hexStr 十六进制字符串
* @return 去除前缀后的字符串
*/
private static String removeHexPrefix(String hexStr) {
if (StrUtil.length(hexStr) > 1) {
final char c0 = hexStr.charAt(0);
switch (c0) {
case '0':
if (hexStr.charAt(1) == 'x' || hexStr.charAt(1) == 'X') {
return hexStr.substring(2);
}
case '#':
return hexStr.substring(1);
}
}
return hexStr;
}
}

View File

@ -888,6 +888,7 @@ public class ReflectUtil {
return (T) ClassUtil.getPrimitiveDefaultValue(type);
}
if (Object.class != type) {
// 某些特殊接口的实例化按照默认实现进行
if (type.isAssignableFrom(AbstractMap.class)) {
type = (Class<T>) HashMap.class;
@ -895,6 +896,11 @@ public class ReflectUtil {
type = (Class<T>) ArrayList.class;
} else if (type.isAssignableFrom(Set.class)) {
type = (Class<T>) HashSet.class;
} else if (type.isAssignableFrom(Queue.class)) {
type = (Class<T>) LinkedList.class;
} else if (type.isAssignableFrom(Deque.class)) {
type = (Class<T>) LinkedList.class;
}
}
try {

View File

@ -130,6 +130,33 @@ public class DateUtilTest {
assertEquals("2020-02-29 12:59:59.000", dateTime.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
}
@Test
public void cellingAmPmTest(){
final String dateStr2 = "2020-02-29 10:59:34";
final Date date2 = DateUtil.parse(dateStr2);
DateTime dateTime = DateUtil.ceiling(date2, DateField.AM_PM);
assertEquals("2020-02-29 11:59:59.999", dateTime.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
dateTime = DateUtil.ceiling(date2, DateField.AM_PM, true);
assertEquals("2020-02-29 11:59:59.000", dateTime.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
}
@Test void roundAmPmTest() {
final String dateStr = "2020-02-29 13:59:34";
final Date date = DateUtil.parse(dateStr);
DateTime dateTime = DateUtil.round(date, DateField.AM_PM);
assertEquals("2020-02-29 12:59:59.000", dateTime.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
final String dateStr2 = "2020-02-29 18:59:34";
final Date date2 = DateUtil.parse(dateStr2);
DateTime dateTime2 = DateUtil.round(date2, DateField.AM_PM);
assertEquals("2020-02-29 23:59:59.000", dateTime2.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
}
@Test
public void ceilingDayTest() {
final String dateStr2 = "2020-02-29 12:59:34";

View File

@ -3,6 +3,7 @@ package cn.hutool.core.util;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
/**
@ -85,4 +86,34 @@ public class HexUtilTest {
final String s1 = HexUtil.decodeHexStr(s);
assertEquals("6", s1);
}
@Test
public void hexToIntTest() {
final String hex1 = "FF";
assertEquals(255, HexUtil.hexToInt(hex1));
final String hex2 = "0xFF";
assertEquals(255, HexUtil.hexToInt(hex2));
final String hex3 = "#FF";
assertEquals(255, HexUtil.hexToInt(hex3));
}
@Test
public void hexToLongTest() {
final String hex1 = "FF";
assertEquals(255L, HexUtil.hexToLong(hex1));
final String hex2 = "0xFF";
assertEquals(255L, HexUtil.hexToLong(hex2));
final String hex3 = "#FF";
assertEquals(255L, HexUtil.hexToLong(hex3));
}
@Test
public void toBigIntegerTest() {
final String hex1 = "FF";
assertEquals(new BigInteger("FF", 16), HexUtil.toBigInteger(hex1));
final String hex2 = "0xFF";
assertEquals(new BigInteger("FF", 16), HexUtil.toBigInteger(hex2));
final String hex3 = "#FF";
assertEquals(new BigInteger("FF", 16), HexUtil.toBigInteger(hex3));
}
}

View File

@ -210,6 +210,7 @@ public class ReflectUtilTest {
private String n;
}
@SuppressWarnings("UnusedReturnValue")
public static Method getMethodWithReturnTypeCheck(final Class<?> clazz, final boolean ignoreCase, final String methodName, final Class<?>... paramTypes) throws SecurityException {
if (null == clazz || StrUtil.isBlank(methodName)) {
return null;
@ -300,6 +301,7 @@ public class ReflectUtilTest {
}
class C2 extends C1 {
@SuppressWarnings("RedundantMethodOverride")
@Override
public void getA() {
@ -371,4 +373,43 @@ public class ReflectUtilTest {
}
}
@Test
public void newInstanceIfPossibleTest2() {
// 测试Object.class不应该被错误地实例化为HashMap应该返回Object实例
Object objectInstance = ReflectUtil.newInstanceIfPossible(Object.class);
assertNotNull(objectInstance);
assertEquals(Object.class, objectInstance.getClass());
// 测试Map.class能够正确实例化为HashMap
Map<?, ?> mapInstance = ReflectUtil.newInstanceIfPossible(Map.class);
assertNotNull(mapInstance);
assertInstanceOf(HashMap.class, mapInstance);
// 测试Collection.class能够正确实例化为ArrayList
Collection<?> collectionInstance = ReflectUtil.newInstanceIfPossible(Collection.class);
assertNotNull(collectionInstance);
assertInstanceOf(ArrayList.class, collectionInstance);
// 测试List.class能够正确实例化为ArrayList
List<?> listInstance = ReflectUtil.newInstanceIfPossible(List.class);
assertNotNull(listInstance);
assertInstanceOf(ArrayList.class, listInstance);
// 测试Set.class能够正确实例化为HashSet
Set<?> setInstance = ReflectUtil.newInstanceIfPossible(Set.class);
assertNotNull(setInstance);
assertInstanceOf(HashSet.class, setInstance);
// 测试Queue接口能够正确实例化为LinkedList
Queue<?> queueInstance = ReflectUtil.newInstanceIfPossible(Queue.class);
assertNotNull(queueInstance);
assertInstanceOf(LinkedList.class, queueInstance);
// 测试Deque接口能够正确实例化为LinkedList
Deque<?> dequeInstance = ReflectUtil.newInstanceIfPossible(Deque.class);
assertNotNull(dequeInstance);
assertInstanceOf(LinkedList.class, dequeInstance);
}
}

View File

@ -13,7 +13,7 @@ import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import java.awt.Font;
import java.awt.*;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
@ -102,7 +102,19 @@ public class Word07Writer implements Closeable {
* @return this
*/
public Word07Writer addText(Font font, String... texts) {
return addText(null, font, texts);
return addText(null, font, null, texts);
}
/**
* 增加一个段落
*
* @param font 字体信息{@link Font}
* @param color 字体颜色{@link Color}
* @param texts 段落中的文本支持多个文本作为一个段落
* @return this
*/
public Word07Writer addText(Font font, Color color, String... texts) {
return addText(null, font, color, texts);
}
/**
@ -114,6 +126,20 @@ public class Word07Writer implements Closeable {
* @return this
*/
public Word07Writer addText(ParagraphAlignment align, Font font, String... texts) {
return addText(align, font, null, texts);
}
/**
* 增加一个段落
*
* @param align 段落对齐方式{@link ParagraphAlignment}
* @param font 字体信息{@link Font}
* @param color 字体颜色{@link Color}
* @param texts 段落中的文本支持多个文本作为一个段落
* @return this
* @since 5.8.42
*/
public Word07Writer addText(ParagraphAlignment align, Font font, Color color, String... texts) {
final XWPFParagraph p = this.doc.createParagraph();
if (null != align) {
p.setAlignment(align);
@ -129,6 +155,10 @@ public class Word07Writer implements Closeable {
run.setBold(font.isBold());
run.setItalic(font.isItalic());
}
if (null != color) {
String hexColor = String.format("%02X", color.getRGB());
run.setColor(hexColor);
}
}
}
return this;

View File

@ -8,7 +8,7 @@ import cn.hutool.core.lang.Console;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.awt.Font;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@ -23,6 +23,7 @@ public class WordWriterTest {
Word07Writer writer = new Word07Writer();
writer.addText(new Font("方正小标宋简体", Font.PLAIN, 22), "我是第一部分", "我是第二部分");
writer.addText(new Font("宋体", Font.PLAIN, 22), "我是正文第一部分", "我是正文第二部分");
writer.addText(new Font("宋体", Font.PLAIN, 22), Color.RED, "我是正文第三部分", "我是正文第四部分");
writer.flush(FileUtil.file("e:/wordWrite.docx"));
writer.close();
Console.log("OK");