Browse Source

add method

Looly 4 years ago
parent
commit
76eb65249a

+ 2 - 0
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)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 7 - 6
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 {
 	}
 
 	/**
-	 * 截取集合的部分
+	 * 截取集合的部分<br>
+	 * 此方法与{@link List#subList(int, int)} 不同在于子列表是新的副本,操作子列表不会影响原列表。
 	 *
 	 * @param <T>   集合元素类型
 	 * @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<T> result = new ArrayList<>();

+ 11 - 0
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<Integer> of = ListUtil.of(1, 2, 3, 4);
+		final List<Integer> sub = ListUtil.sub(of, 2, 4);
+		sub.remove(0);
+
+		// 对子列表操作不影响原列表
+		Assert.assertEquals(4, of.size());
+		Assert.assertEquals(1, sub.size());
+	}
 }

+ 13 - 11
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<Long> 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<Long> set = new ConcurrentHashSet<>();
-		
+
 		//线程数
 		int threadCount = 100;
 		//每个线程生成的ID数
@@ -123,7 +125,7 @@ public class IdUtilTest {
 				latch.countDown();
 			});
 		}
-		
+
 		//等待全部线程结束
 		try {
 			latch.await();

+ 31 - 0
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;
 
@@ -194,6 +196,35 @@ public class SmUtil {
 	}
 
 	/**
+	 * 将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<br>
 	 * 来自:https://blog.csdn.net/pridas/article/details/86118774
 	 *

+ 6 - 6
hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java

@@ -62,8 +62,8 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
 	 * 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
 	 * 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
 	 *
-	 * @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<SM2> {
 	 * 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
 	 * 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
 	 *
-	 * @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<SM2> {
 	 * 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
 	 * 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
 	 *
-	 * @param privateKeyParams 私钥
-	 * @param publicKeyParams  公钥
+	 * @param privateKeyParams 私钥,可以为null
+	 * @param publicKeyParams  公钥,可以为null
 	 */
 	public SM2(ECPrivateKeyParameters privateKeyParams, ECPublicKeyParameters publicKeyParams) {
 		super(ALGORITHM_SM2, null, null);