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);