diff --git a/CHANGELOG.md b/CHANGELOG.md index 24a1efd63..35d6c3b6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ * 【extra 】 修复Ftp中异常参数没有传入问题(issue#1397@Github) * 【crypto 】 修复Sm2使用D构造空指针问题(issue#I37Z4C@Gitee) * 【poi 】 修复ExcelPicUtil中图表报错问题(issue#I38857@Gitee) +* 【core 】 修复ListUtil.page方法返回空列表无法编辑问题(issue#1415@Github) +* 【core 】 修复ListUtil.sub中step不通结果不一致问题(issue#1409@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java index f445e2927..088e19787 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java @@ -246,7 +246,7 @@ public class ListUtil { // 每页条目数大于总数直接返回所有 if (resultSize <= pageSize) { if (pageNo < (PageUtil.getFirstPageNo() + 1)) { - return Collections.unmodifiableList(list); + return unmodifiable(list); } else { // 越界直接返回空 return new ArrayList<>(0); @@ -262,11 +262,11 @@ public class ListUtil { if (startEnd[1] > resultSize) { startEnd[1] = resultSize; if (startEnd[0] > startEnd[1]) { - return empty(); + return new ArrayList<>(0); } } - return list.subList(startEnd[0], startEnd[1]); + return sub(list, startEnd[0], startEnd[1]); } /** @@ -366,7 +366,8 @@ public class ListUtil { } /** - * 截取集合的部分 + * 截取集合的部分
+ * 此方法与{@link List#subList(int, int)} 不同在于子列表是新的副本,操作子列表不会影响原列表。 * * @param 集合元素类型 * @param list 被截取的数组 @@ -407,8 +408,8 @@ public class ListUtil { end = size; } - if (step <= 1) { - return list.subList(start, end); + if (step < 1) { + step = 1; } final List result = new ArrayList<>(); diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/ListUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/ListUtilTest.java index 86c9664dc..46c94cdd5 100644 --- a/hutool-core/src/test/java/cn/hutool/core/collection/ListUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/collection/ListUtilTest.java @@ -101,4 +101,15 @@ public class ListUtilTest { int[] d1 = ListUtil.page(0,8,a).stream().mapToInt(Integer::valueOf).toArray(); Assert.assertArrayEquals(new int[]{1,2,3,4,5},d1); } + + @Test + public void subTest(){ + final List of = ListUtil.of(1, 2, 3, 4); + final List sub = ListUtil.sub(of, 2, 4); + sub.remove(0); + + // 对子列表操作不影响原列表 + Assert.assertEquals(4, of.size()); + Assert.assertEquals(1, sub.size()); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/IdUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/IdUtilTest.java index f9304b18d..ba4eba07b 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/IdUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/IdUtilTest.java @@ -17,7 +17,7 @@ import java.util.concurrent.CountDownLatch; /** * {@link IdUtil} 单元测试 - * + * * @author looly * */ @@ -31,12 +31,12 @@ public class IdUtilTest { String randomUUID = IdUtil.randomUUID(); Assert.assertEquals(36, randomUUID.length()); } - + @Test public void fastUUIDTest() { String simpleUUID = IdUtil.fastSimpleUUID(); Assert.assertEquals(32, simpleUUID.length()); - + String randomUUID = IdUtil.fastUUID(); Assert.assertEquals(36, randomUUID.length()); } @@ -60,25 +60,26 @@ public class IdUtilTest { } Console.log(timer.interval()); } - + @Test public void objectIdTest() { String id = IdUtil.objectId(); Assert.assertEquals(24, id.length()); } - + @Test public void createSnowflakeTest() { Snowflake snowflake = IdUtil.createSnowflake(1, 1); long id = snowflake.nextId(); Assert.assertTrue(id > 0); } - + @Test + @Ignore public void snowflakeBenchTest() { final Set set = new ConcurrentHashSet<>(); final Snowflake snowflake = IdUtil.createSnowflake(1, 1); - + //线程数 int threadCount = 100; //每个线程生成的ID数 @@ -94,7 +95,7 @@ public class IdUtilTest { latch.countDown(); }); } - + //等待全部线程结束 try { latch.await(); @@ -103,11 +104,12 @@ public class IdUtilTest { } Assert.assertEquals(threadCount * idCountPerThread, set.size()); } - + @Test + @Ignore public void snowflakeBenchTest2() { final Set set = new ConcurrentHashSet<>(); - + //线程数 int threadCount = 100; //每个线程生成的ID数 @@ -123,7 +125,7 @@ public class IdUtilTest { latch.countDown(); }); } - + //等待全部线程结束 try { latch.await(); diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java index 861768492..f3cb8083d 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java @@ -16,6 +16,8 @@ import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.gm.GMNamedCurves; import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.signers.DSAEncoding; +import org.bouncycastle.crypto.signers.StandardDSAEncoding; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; @@ -193,6 +195,35 @@ public class SmUtil { return result; } + /** + * 将sm2签名结果解码为R和S值 + * + * @param encoding {@link DSAEncoding} + * @param rsDer 签名结果的DER表示形式 + * @return R和S值,结果为64位,前32位为R,后32为为S + * @since 5.5.9 + */ + public static byte[] decode(DSAEncoding encoding, byte[] rsDer){ + if(null == encoding){ + encoding = StandardDSAEncoding.INSTANCE; + } + + final BigInteger[] decode; + try { + decode = encoding.decode(SM2_DOMAIN_PARAMS.getN(), rsDer); + } catch (IOException e) { + throw new IORuntimeException(e); + } + + byte[] r = bigIntToFixedLengthBytes(decode[0]); + byte[] s = bigIntToFixedLengthBytes(decode[1]); + byte[] result = new byte[RS_LEN * 2]; + System.arraycopy(r, 0, result, 0, r.length); + System.arraycopy(s, 0, result, RS_LEN, s.length); + + return result; + } + /** * BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
* 来自:https://blog.csdn.net/pridas/article/details/86118774 diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java index e22c9402c..8a26f5d95 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java @@ -62,8 +62,8 @@ public class SM2 extends AbstractAsymmetricCrypto { * 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密 * - * @param privateKeyStr 私钥Hex或Base64表示 - * @param publicKeyStr 公钥Hex或Base64表示 + * @param privateKeyStr 私钥Hex或Base64表示,必须使用PKCS#8规范 + * @param publicKeyStr 公钥Hex或Base64表示,必须使用X509规范 */ public SM2(String privateKeyStr, String publicKeyStr) { this(SecureUtil.decode(privateKeyStr), SecureUtil.decode(publicKeyStr)); @@ -74,8 +74,8 @@ public class SM2 extends AbstractAsymmetricCrypto { * 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密 * - * @param privateKey 私钥 - * @param publicKey 公钥 + * @param privateKey 私钥,必须使用PKCS#8规范 + * @param publicKey 公钥,必须使用X509规范 */ public SM2(byte[] privateKey, byte[] publicKey) { this(// @@ -135,8 +135,8 @@ public class SM2 extends AbstractAsymmetricCrypto { * 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密 * - * @param privateKeyParams 私钥 - * @param publicKeyParams 公钥 + * @param privateKeyParams 私钥,可以为null + * @param publicKeyParams 公钥,可以为null */ public SM2(ECPrivateKeyParameters privateKeyParams, ECPublicKeyParameters publicKeyParams) { super(ALGORITHM_SM2, null, null);