From d6906aa85efee00725b92389b76df4ef90c5d59e Mon Sep 17 00:00:00 2001 From: lin Date: Wed, 12 Jan 2022 12:21:33 +0800 Subject: [PATCH 01/98] add Lenovo ua regex --- .../java/cn/hutool/http/useragent/Browser.java | 2 ++ .../hutool/http/useragent/UserAgentUtilTest.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java b/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java index 97de1025c..e5e7c05d1 100644 --- a/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java +++ b/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java @@ -47,6 +47,8 @@ public class Browser extends UserAgentInfo { new Browser("UCBrowser", "UC?Browser", "UC?Browser\\/([\\d\\w\\.\\-]+)"), // 夸克浏览器 new Browser("Quark", "Quark", Other_Version), + // 联想浏览器 + new Browser("Lenovo", "SLBrowser", "SLBrowser/([\\d\\w\\.\\-]+)"), new Browser("MSEdge", "Edge|Edg", "(?:edge|Edg|EdgA)\\/([\\d\\w\\.\\-]+)"), new Browser("Chrome", "chrome", Other_Version), diff --git a/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java index 49cc4fe02..066338152 100644 --- a/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java @@ -373,4 +373,20 @@ public class UserAgentUtilTest { Assert.assertEquals("Android", ua.getPlatform().toString()); Assert.assertTrue(ua.isMobile()); } + + @Test + public void parseLenovoTest(){ + // https://gitee.com/dromara/hutool/issues/I4MCBP + String uaStr = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/30"; + final UserAgent ua = UserAgentUtil.parse(uaStr); + + Assert.assertEquals("Lenovo", ua.getBrowser().toString()); + Assert.assertEquals("7.0.0.6241", ua.getVersion()); + Assert.assertEquals("Webkit", ua.getEngine().toString()); + Assert.assertEquals("537.36", ua.getEngineVersion()); + Assert.assertEquals("Windows 10 or Windows Server 2016", ua.getOs().toString()); + Assert.assertEquals("10.0", ua.getOsVersion()); + Assert.assertEquals("Windows", ua.getPlatform().toString()); + Assert.assertFalse(ua.isMobile()); + } } From e86519d6fc92005588f9a9e48b07d7c0f79fbf54 Mon Sep 17 00:00:00 2001 From: lin Date: Wed, 12 Jan 2022 12:21:59 +0800 Subject: [PATCH 02/98] add Lenovo ua regex --- .../test/java/cn/hutool/http/useragent/UserAgentUtilTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java index 066338152..d675adf4d 100644 --- a/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java @@ -376,7 +376,7 @@ public class UserAgentUtilTest { @Test public void parseLenovoTest(){ - // https://gitee.com/dromara/hutool/issues/I4MCBP + // https://gitee.com/dromara/hutool/issues/I4QBMD String uaStr = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/30"; final UserAgent ua = UserAgentUtil.parse(uaStr); From d324f785d7cf236ae02437b20cc11a3b673bb669 Mon Sep 17 00:00:00 2001 From: Golden Looly Date: Fri, 14 Jan 2022 09:45:04 +0800 Subject: [PATCH 03/98] Revert "add Lenovo Browser ua regex " --- .../java/cn/hutool/http/useragent/Browser.java | 2 -- .../hutool/http/useragent/UserAgentUtilTest.java | 16 ---------------- 2 files changed, 18 deletions(-) diff --git a/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java b/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java index e5e7c05d1..97de1025c 100644 --- a/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java +++ b/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java @@ -47,8 +47,6 @@ public class Browser extends UserAgentInfo { new Browser("UCBrowser", "UC?Browser", "UC?Browser\\/([\\d\\w\\.\\-]+)"), // 夸克浏览器 new Browser("Quark", "Quark", Other_Version), - // 联想浏览器 - new Browser("Lenovo", "SLBrowser", "SLBrowser/([\\d\\w\\.\\-]+)"), new Browser("MSEdge", "Edge|Edg", "(?:edge|Edg|EdgA)\\/([\\d\\w\\.\\-]+)"), new Browser("Chrome", "chrome", Other_Version), diff --git a/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java index d675adf4d..49cc4fe02 100644 --- a/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java @@ -373,20 +373,4 @@ public class UserAgentUtilTest { Assert.assertEquals("Android", ua.getPlatform().toString()); Assert.assertTrue(ua.isMobile()); } - - @Test - public void parseLenovoTest(){ - // https://gitee.com/dromara/hutool/issues/I4QBMD - String uaStr = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/30"; - final UserAgent ua = UserAgentUtil.parse(uaStr); - - Assert.assertEquals("Lenovo", ua.getBrowser().toString()); - Assert.assertEquals("7.0.0.6241", ua.getVersion()); - Assert.assertEquals("Webkit", ua.getEngine().toString()); - Assert.assertEquals("537.36", ua.getEngineVersion()); - Assert.assertEquals("Windows 10 or Windows Server 2016", ua.getOs().toString()); - Assert.assertEquals("10.0", ua.getOsVersion()); - Assert.assertEquals("Windows", ua.getPlatform().toString()); - Assert.assertFalse(ua.isMobile()); - } } From 74c1aa12a3f4b6003aa8525e769e5c9d9f48ad7e Mon Sep 17 00:00:00 2001 From: lsx0310 Date: Mon, 24 Jan 2022 23:53:26 +0800 Subject: [PATCH 04/98] =?UTF-8?q?=E5=A2=9E=E5=8A=A0MetroHash=E7=AE=97?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/lang/hash/MetroHash.java | 233 ++++++++++++++++++ .../java/cn/hutool/core/util/HashUtil.java | 86 +++++++ .../cn/hutool/core/lang/MetroHashTest.java | 81 ++++++ hutool-cuckooFilter/pom.xml | 26 ++ pom.xml | 3 +- 5 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/hash/MetroHash.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/lang/MetroHashTest.java create mode 100644 hutool-cuckooFilter/pom.xml diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/MetroHash.java b/hutool-core/src/main/java/cn/hutool/core/lang/hash/MetroHash.java new file mode 100644 index 000000000..e86dc3d97 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/hash/MetroHash.java @@ -0,0 +1,233 @@ +package cn.hutool.core.lang.hash; + +import java.util.Arrays; + +/** + * Apache 发布的MetroHash算法,是一组用于非加密用例的最先进的哈希函数。 + * 除了卓越的性能外,他们还以算法生成而著称。 + * + *

+ * 官方实现:https://github.com/jandrewrogers/MetroHash + * 官方文档:http://www.jandrewrogers.com/2015/05/27/metrohash/ + * Go语言实现:https://github.com/linvon/cuckoo-filter/blob/main/vendor/github.com/dgryski/go-metro/ + * @author li + */ + +public class MetroHash { + + /** + * hash64 种子加盐 + */ + private final static long k0_64 = 0xD6D018F5; + private final static long k1_64 = 0xA2AA033B; + private final static long k2_64 = 0x62992FC1; + private final static long k3_64 = 0x30BC5B29; + + /** + * hash128 种子加盐 + */ + private final static long k0_128 = 0xC83A91E1; + private final static long k1_128 = 0x8648DBDB; + private final static long k2_128 = 0x7BDEC03B; + private final static long k3_128 = 0x2F5870A5; + + public static long hash64(String str) { + return hash64(str, 1337); + } + + public static long hash64(byte[] data) { + return hash64(data, 1337); + } + + public static long hash64(String str, long seed) { + return hash64(str.getBytes(), seed); + } + + public static Number128 hash128(String str) { + return hash128(str, 1337); + } + + public static Number128 hash128(byte[] data) { + return hash128(data, 1337); + } + + public static Number128 hash128(String str, long seed) { + return hash128(str.getBytes(), seed); + } + + public static long hash64(byte[] data, long seed) { + byte[] buffer = data; + long hash = (seed + k2_64) * k0_64; + + long v0, v1, v2, v3; + v0 = hash; + v1 = hash; + v2 = hash; + v3 = hash; + + if (buffer.length >= 32) { + + while (buffer.length >= 32) { + v0 += littleEndian64(Arrays.copyOfRange(buffer, 0, 8)) * k0_64; + v0 = rotateLeft64(v0, -29) + v2; + v1 += littleEndian64(Arrays.copyOfRange(buffer, 8, 16)) * k1_64; + v1 = rotateLeft64(v1, -29) + v3; + v2 += littleEndian64(Arrays.copyOfRange(buffer, 16, 24)) * k2_64; + v2 = rotateLeft64(v2, -29) + v0; + v3 += littleEndian64(Arrays.copyOfRange(buffer, 24, 32)) * k3_64; + v3 = rotateLeft64(v3, -29) + v1; + buffer = Arrays.copyOfRange(buffer, 32, buffer.length); + } + + v2 ^= rotateLeft64(((v0 + v3) * k0_64) + v1, -37) * k1_64; + v3 ^= rotateLeft64(((v1 + v2) * k1_64) + v0, -37) * k0_64; + v0 ^= rotateLeft64(((v0 + v2) * k0_64) + v3, -37) * k1_64; + v1 ^= rotateLeft64(((v1 + v3) * k1_64) + v2, -37) * k0_64; + hash += v0 ^ v1; + } + + if (buffer.length >= 16) { + v0 = hash + littleEndian64(Arrays.copyOfRange(buffer, 0, 8)) * k2_64; + v0 = rotateLeft64(v0, -29) * k3_64; + v1 = hash + littleEndian64(Arrays.copyOfRange(buffer, 8, 16)) * k2_64; + v1 = rotateLeft64(v1, -29) * k3_64; + v0 ^= rotateLeft64(v0 * k0_64, -21) + v1; + v1 ^= rotateLeft64(v1 * k3_64, -21) + v0; + hash += v1; + buffer = Arrays.copyOfRange(buffer, 16, buffer.length); + } + + if (buffer.length >= 8) { + hash += littleEndian64(Arrays.copyOfRange(buffer, 0, 8)) * k3_64; + buffer = Arrays.copyOfRange(buffer, 8, buffer.length); + hash ^= rotateLeft64(hash, -55) * k1_64; + } + + if (buffer.length >= 4) { + hash += (long) littleEndian32(Arrays.copyOfRange(buffer, 0, 4)) * k3_64; + hash ^= rotateLeft64(hash, -26) * k1_64; + buffer = Arrays.copyOfRange(buffer, 4, buffer.length); + } + + if (buffer.length >= 2) { + hash += (long) littleEndian16(Arrays.copyOfRange(buffer, 0, 2)) * k3_64; + buffer = Arrays.copyOfRange(buffer, 2, buffer.length); + hash ^= rotateLeft64(hash, -48) * k1_64; + } + + if (buffer.length >= 1) { + hash += (long) buffer[0] * k3_64; + hash ^= rotateLeft64(hash, -38) * k1_64; + } + + hash ^= rotateLeft64(hash, -28); + hash *= k0_64; + hash ^= rotateLeft64(hash, -29); + + return hash; + } + + + public static Number128 hash128(byte[] data, long seed) { + byte[] buffer = data; + + long v0, v1, v2, v3; + + v0 = (seed - k0_128) * k3_128; + v1 = (seed + k1_128) * k2_128; + + if (buffer.length >= 32) { + v2 = (seed + k0_128) * k2_128; + v3 = (seed - k1_128) * k3_128; + + while (buffer.length >= 32) { + v0 += littleEndian64(buffer) * k0_128; + buffer = Arrays.copyOfRange(buffer, 8, buffer.length); + v0 = rotateRight(v0, 29) + v2; + v1 += littleEndian64(buffer) * k1_128; + buffer = Arrays.copyOfRange(buffer, 8, buffer.length); + v1 = rotateRight(v1, 29) + v3; + v2 += littleEndian64(buffer) * k2_128; + buffer = Arrays.copyOfRange(buffer, 8, buffer.length); + v2 = rotateRight(v2, 29) + v0; + v3 = littleEndian64(buffer) * k3_128; + buffer = Arrays.copyOfRange(buffer, 8, buffer.length); + v3 = rotateRight(v3, 29) + v1; + } + + v2 ^= rotateRight(((v0 + v3) * k0_128) + v1, 21) * k1_128; + v3 ^= rotateRight(((v1 + v2) * k1_128) + v0, 21) * k0_128; + v0 ^= rotateRight(((v0 + v2) * k0_128) + v3, 21) * k1_128; + v1 ^= rotateRight(((v1 + v3) * k1_128) + v2, 21) * k0_128; + } + + if (buffer.length >= 16) { + v0 += littleEndian64(buffer) * k2_128; + buffer = Arrays.copyOfRange(buffer, 8, buffer.length); + v0 = rotateRight(v0, 33) * k3_128; + v1 += littleEndian64(buffer) * k2_128; + buffer = Arrays.copyOfRange(buffer, 8, buffer.length); + v1 = rotateRight(v1, 33) * k3_128; + v0 ^= rotateRight((v0 * k2_128) + v1, 45) + k1_128; + v1 ^= rotateRight((v1 * k3_128) + v0, 45) + k0_128; + } + + if (buffer.length >= 8) { + v0 += littleEndian64(buffer) * k2_128; + buffer = Arrays.copyOfRange(buffer, 8, buffer.length); + v0 = rotateRight(v0, 33) * k3_128; + v0 ^= rotateRight((v0 * k2_128) + v1, 27) * k1_128; + } + + if (buffer.length >= 4) { + v1 += (long) littleEndian32(buffer) * k2_128; + buffer = Arrays.copyOfRange(buffer, 4, buffer.length); + v1 = rotateRight(v1, 33) * k3_128; + v1 ^= rotateRight((v1 * k3_128) + v0, 46) * k0_128; + } + + if (buffer.length >= 2) { + v0 += (long) littleEndian16(buffer) * k2_128; + buffer = Arrays.copyOfRange(buffer, 2, buffer.length); + v0 = rotateRight(v0, 33) * k3_128; + v0 ^= rotateRight((v0 * k2_128) * v1, 22) * k1_128; + } + + if (buffer.length >= 1) { + v1 += (long) buffer[0] * k2_128; + v1 = rotateRight(v1, 33) * k3_128; + v1 ^= rotateRight((v1 * k3_128) + v0, 58) * k0_128; + } + + v0 += rotateRight((v0 * k0_128) + v1, 13); + v1 += rotateRight((v1 * k1_128) + v0, 37); + v0 += rotateRight((v0 * k2_128) + v1, 13); + v1 += rotateRight((v1 * k3_128) + v0, 37); + + return new Number128(v0, v1); + } + + + private static long littleEndian64(byte[] b) { + return (long) b[0] | (long) (b[1]) << 8 | (long) b[2] << 16 | (long) b[3] << 24 | + (long) b[4] << 32 | (long) b[5] << 40 | (long) b[6] << 48 | (long) b[7] << 56; + } + + private static int littleEndian32(byte[] b) { + return (int) b[0] | (int) b[1] << 8 | (int) b[2] << 16 | (int) b[3] << 24; + } + + private static int littleEndian16(byte[] b) { + return (short) b[0] | (short) b[1] << 8; + } + + private static long rotateLeft64(long x, int k) { + int n = 64; + int s = k & (n - 1); + return x << s | x >> (n - s); + } + + private static long rotateRight(long val, int shift) { + return (val >> shift) | (val << (64 - shift)); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/util/HashUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/HashUtil.java index 97ee1537b..5bd64d5aa 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/HashUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/HashUtil.java @@ -1,6 +1,7 @@ package cn.hutool.core.util; import cn.hutool.core.lang.hash.CityHash; +import cn.hutool.core.lang.hash.MetroHash; import cn.hutool.core.lang.hash.MurmurHash; import cn.hutool.core.lang.hash.Number128; @@ -545,4 +546,89 @@ public class HashUtil { public static long[] cityHash128(byte[] data, Number128 seed) { return CityHash.hash128(data, seed).getLongArray(); } + + /** + * MetroHash 算法64-bit实现 + * + * @param data 数据 + * @param seed 种子 + * @return + */ + public static long metroHash64(byte[] data, long seed) { + return MetroHash.hash64(data, seed); + } + + /** + * MetroHash 算法64-bit实现 + * + * @param data 数据 + * @return + */ + public static long metroHash64(byte[] data) { + return MetroHash.hash64(data); + } + + /** + * MetroHash 算法64-bit实现 + * + * @param str 数据 + * @param seed 种子 + * @return + */ + public static long metroHash64(String str,long seed) { + return MetroHash.hash64(str,seed); + } + + /** + * MetroHash 算法64-bit实现 + * + * @param str 数据 + * @return + */ + public static long metroHash64(String str) { + return MetroHash.hash64(str); + } + + /** + * MetroHash 算法128-bit实现 + * + * @param data 数据 + * @param seed 种子 + * @return hash值,long[0]:低位,long[1]:高位 + */ + public static long[] metroHash128(byte[] data, long seed) { + return MetroHash.hash128(data,seed).getLongArray(); + } + + /** + * MetroHash 算法128-bit实现 + * + * @param data 数据 + * @return hash值,long[0]:低位,long[1]:高位 + */ + public static long[] metroHash128(byte[] data) { + return MetroHash.hash128(data).getLongArray(); + } + + /** + * MetroHash 算法128-bit实现 + * + * @param str 数据 + * @return hash值,long[0]:低位,long[1]:高位 + */ + public static long[] metroHash128(String str) { + return MetroHash.hash128(str).getLongArray(); + } + + /** + * MetroHash 算法128-bit实现 + * + * @param str 数据 + * @param seed 种子 + * @return hash值,long[0]:低位,long[1]:高位 + */ + public static long[] metroHash128(String str, long seed) { + return MetroHash.hash128(str,seed).getLongArray(); + } + } diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/MetroHashTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/MetroHashTest.java new file mode 100644 index 000000000..b30b5f9f7 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/lang/MetroHashTest.java @@ -0,0 +1,81 @@ +package cn.hutool.core.lang; + + +import cn.hutool.core.lang.hash.CityHash; +import cn.hutool.core.lang.hash.MetroHash; +import org.junit.Test; + +import java.util.Random; + +public class MetroHashTest { + + + /** + * 数据量越大 MetroHash 优势越明显, + */ + @Test + public void bulkHashing64Test() { + String[] strArray = getRandomStringArray(10000000); + long startCity = System.currentTimeMillis(); + for (String s : strArray) { + CityHash.hash64(s.getBytes()); + } + long endCity = System.currentTimeMillis(); + + long startMetro = System.currentTimeMillis(); + for (String s : strArray) { + MetroHash.hash64(s); + } + long endMetro = System.currentTimeMillis(); + + System.out.println("metroHash =============" + (endMetro - startMetro)); + System.out.println("cityHash =============" + (endCity - startCity)); + } + + + /** + * 数据量越大 MetroHash 优势越明显, + */ + @Test + public void bulkHashing128Test() { + String[] strArray = getRandomStringArray(10000000); + long startCity = System.currentTimeMillis(); + for (String s : strArray) { + CityHash.hash128(s.getBytes()); + } + long endCity = System.currentTimeMillis(); + + long startMetro = System.currentTimeMillis(); + for (String s : strArray) { + MetroHash.hash128(s); + } + long endMetro = System.currentTimeMillis(); + + System.out.println("metroHash =============" + (endMetro - startMetro)); + System.out.println("cityHash =============" + (endCity - startCity)); + } + + + private static String[] getRandomStringArray(int length) { + String[] result = new String[length]; + Random random = new Random(); + int index = 0; + while (index < length) { + result[index++] = getRandomString(random.nextInt(64)); + } + return result; + } + + private static String getRandomString(int length) { + String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + Random random = new Random(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < length; i++) { + int number = random.nextInt(62); + sb.append(str.charAt(number)); + } + return sb.toString(); + } + + +} diff --git a/hutool-cuckooFilter/pom.xml b/hutool-cuckooFilter/pom.xml new file mode 100644 index 000000000..793315b04 --- /dev/null +++ b/hutool-cuckooFilter/pom.xml @@ -0,0 +1,26 @@ + + + + hutool-parent + cn.hutool + 5.7.19 + + 4.0.0 + jar + + hutool-cuckooFilter + ${project.artifactId} + Hutool 布谷鸟过滤器 + + + + + cn.hutool + hutool-core + ${project.parent.version} + + + + diff --git a/pom.xml b/pom.xml index 673cdadb7..6d2609f28 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,8 @@ hutool-captcha hutool-socket hutool-jwt - + hutool-cuckooFilter + utf-8 From bdeae6f02ebfc368c0f228fb302d27fb2b703ebd Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 7 Jan 2022 21:14:54 +0800 Subject: [PATCH 05/98] prepare 5.7.20 --- CHANGELOG.md | 6 ++++++ README-EN.md | 6 +++--- README.md | 6 +++--- bin/version.txt | 2 +- docs/js/version.js | 2 +- hutool-all/pom.xml | 2 +- hutool-aop/pom.xml | 2 +- hutool-bloomFilter/pom.xml | 2 +- hutool-bom/pom.xml | 2 +- hutool-cache/pom.xml | 2 +- hutool-captcha/pom.xml | 2 +- hutool-core/pom.xml | 2 +- hutool-cron/pom.xml | 2 +- hutool-crypto/pom.xml | 2 +- hutool-db/pom.xml | 2 +- hutool-dfa/pom.xml | 2 +- hutool-extra/pom.xml | 2 +- hutool-http/pom.xml | 2 +- hutool-json/pom.xml | 2 +- hutool-jwt/pom.xml | 2 +- hutool-log/pom.xml | 2 +- hutool-poi/pom.xml | 2 +- hutool-script/pom.xml | 2 +- hutool-setting/pom.xml | 2 +- hutool-socket/pom.xml | 2 +- hutool-system/pom.xml | 2 +- pom.xml | 2 +- 27 files changed, 36 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 208ee2fe9..95e774205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ ------------------------------------------------------------------------------------------------------------- +# 5.7.20 (2022-01-07) + +### 🐣新特性 +### 🐞Bug修复 + +------------------------------------------------------------------------------------------------------------- # 5.7.19 (2022-01-07) ### 🐣新特性 diff --git a/README-EN.md b/README-EN.md index 07ec93b86..b55c1128d 100644 --- a/README-EN.md +++ b/README-EN.md @@ -142,18 +142,18 @@ We provide the T-Shirt and Sweater with Hutool Logo, please visit the shop: cn.hutool hutool-all - 5.7.19 + 5.7.20 ``` ### 🍐Gradle ``` -implementation 'cn.hutool:hutool-all:5.7.19' +implementation 'cn.hutool:hutool-all:5.7.20' ``` ## 📥Download -- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.7.19/) +- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.7.20/) > 🔔️note: > Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available. diff --git a/README.md b/README.md index aa2154e23..8aeb70262 100644 --- a/README.md +++ b/README.md @@ -142,20 +142,20 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不 cn.hutool hutool-all - 5.7.19 + 5.7.20 ``` ### 🍐Gradle ``` -implementation 'cn.hutool:hutool-all:5.7.19' +implementation 'cn.hutool:hutool-all:5.7.20' ``` ### 📥下载jar 点击以下链接,下载`hutool-all-X.X.X.jar`即可: -- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.7.19/) +- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.7.20/) > 🔔️注意 > Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。 diff --git a/bin/version.txt b/bin/version.txt index 1ccc37576..b0917fb0e 100755 --- a/bin/version.txt +++ b/bin/version.txt @@ -1 +1 @@ -5.7.19 +5.7.20 diff --git a/docs/js/version.js b/docs/js/version.js index 90d3c3b3a..978cfac6d 100644 --- a/docs/js/version.js +++ b/docs/js/version.js @@ -1 +1 @@ -var version = '5.7.19' \ No newline at end of file +var version = '5.7.20' \ No newline at end of file diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml index 9dbbfdc1f..10a7032a4 100644 --- a/hutool-all/pom.xml +++ b/hutool-all/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-all diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml index 35e36768f..edc46b7a7 100644 --- a/hutool-aop/pom.xml +++ b/hutool-aop/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-aop diff --git a/hutool-bloomFilter/pom.xml b/hutool-bloomFilter/pom.xml index 82e8163aa..abeaec1c1 100644 --- a/hutool-bloomFilter/pom.xml +++ b/hutool-bloomFilter/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-bloomFilter diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml index 2db026910..3b8ad4fd4 100644 --- a/hutool-bom/pom.xml +++ b/hutool-bom/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-bom diff --git a/hutool-cache/pom.xml b/hutool-cache/pom.xml index 91a94dc0d..d544b5527 100644 --- a/hutool-cache/pom.xml +++ b/hutool-cache/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-cache diff --git a/hutool-captcha/pom.xml b/hutool-captcha/pom.xml index 4bd96f6e5..5dd8f9f15 100644 --- a/hutool-captcha/pom.xml +++ b/hutool-captcha/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-captcha diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml index 2548d3862..0129bcab8 100644 --- a/hutool-core/pom.xml +++ b/hutool-core/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-core diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml index ba2fdbfd2..d95c455b4 100644 --- a/hutool-cron/pom.xml +++ b/hutool-cron/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-cron diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml index 46da18d6b..50f7356ac 100644 --- a/hutool-crypto/pom.xml +++ b/hutool-crypto/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-crypto diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml index 7b35e41ad..92fe54fa8 100644 --- a/hutool-db/pom.xml +++ b/hutool-db/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-db diff --git a/hutool-dfa/pom.xml b/hutool-dfa/pom.xml index 37bd3ae42..183c0eff9 100644 --- a/hutool-dfa/pom.xml +++ b/hutool-dfa/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-dfa diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml index 2fd49d272..7fca763ac 100644 --- a/hutool-extra/pom.xml +++ b/hutool-extra/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-extra diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index de2525d33..a27a4ac72 100644 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-http diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml index ef9c36c8a..5103dc136 100644 --- a/hutool-json/pom.xml +++ b/hutool-json/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-json diff --git a/hutool-jwt/pom.xml b/hutool-jwt/pom.xml index f818fc158..7520a39c4 100644 --- a/hutool-jwt/pom.xml +++ b/hutool-jwt/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-jwt diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml index 0d97e4362..075926147 100644 --- a/hutool-log/pom.xml +++ b/hutool-log/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-log diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml index 826579e9c..f80d0c8e9 100644 --- a/hutool-poi/pom.xml +++ b/hutool-poi/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-poi diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml index 7a6c33e2c..21854b669 100644 --- a/hutool-script/pom.xml +++ b/hutool-script/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-script diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml index cbbc6a4c9..107bd6367 100644 --- a/hutool-setting/pom.xml +++ b/hutool-setting/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-setting diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml index 1839e22bf..26529bfd2 100644 --- a/hutool-socket/pom.xml +++ b/hutool-socket/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-socket diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml index 0e2f0ec12..ca87e5d2d 100644 --- a/hutool-system/pom.xml +++ b/hutool-system/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool-system diff --git a/pom.xml b/pom.xml index 6d2609f28..b6cee2017 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.7.19 + 5.7.20-SNAPSHOT hutool Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。 https://github.com/dromara/hutool From 6ed92bfacf869a09d5d7616512030c46c98c7a7c Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 8 Jan 2022 13:36:57 +0800 Subject: [PATCH 06/98] fix bug --- CHANGELOG.md | 3 +- .../java/cn/hutool/core/bean/BeanDesc.java | 44 ++++------- .../java/cn/hutool/core/bean/BeanUtil.java | 7 +- .../core/lang/reflect/MethodHandleUtil.java | 5 +- .../java/cn/hutool/core/util/ReflectUtil.java | 78 ++++++++++++++++++- .../cn/hutool/core/bean/Issue2082Test.java | 33 ++++++++ 6 files changed, 129 insertions(+), 41 deletions(-) create mode 100755 hutool-core/src/test/java/cn/hutool/core/bean/Issue2082Test.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 95e774205..aba46ae03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,11 @@ ------------------------------------------------------------------------------------------------------------- -# 5.7.20 (2022-01-07) +# 5.7.20 (2022-01-08) ### 🐣新特性 ### 🐞Bug修复 +* 【core 】 修复setter重载导致匹配错误(issue#2082@Github) ------------------------------------------------------------------------------------------------------------- # 5.7.19 (2022-01-07) diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java b/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java index 65411b497..976f40d29 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java @@ -140,14 +140,12 @@ public class BeanDesc implements Serializable { * @return this */ private BeanDesc init() { - final Method[] methods = ReflectUtil.getMethods(this.beanClass); + final Method[] gettersAndSetters = ReflectUtil.getMethods(this.beanClass, ReflectUtil::isGetterOrSetterIgnoreCase); PropDesc prop; for (Field field : ReflectUtil.getFields(this.beanClass)) { - if (false == ModifierUtil.isStatic(field) && - // 排除对象子类 - false == "this$0".equals(field.getName())) { - //只针对非static属性 - prop = createProp(field, methods); + // 排除静态属性和对象子类 + if (false == ModifierUtil.isStatic(field) && false == ReflectUtil.isOuterClassField(field)) { + prop = createProp(field, gettersAndSetters); // 只有不存在时才放入,防止父类属性覆盖子类属性 this.propMap.putIfAbsent(prop.getFieldName(), prop); } @@ -190,12 +188,12 @@ public class BeanDesc implements Serializable { /** * 查找字段对应的Getter和Setter方法 * - * @param field 字段 - * @param methods 类中所有的方法 - * @param ignoreCase 是否忽略大小写匹配 + * @param field 字段 + * @param gettersOrSetters 类中所有的Getter或Setter方法 + * @param ignoreCase 是否忽略大小写匹配 * @return PropDesc */ - private PropDesc findProp(Field field, Method[] methods, boolean ignoreCase) { + private PropDesc findProp(Field field, Method[] gettersOrSetters, boolean ignoreCase) { final String fieldName = field.getName(); final Class fieldType = field.getType(); final boolean isBooleanField = BooleanUtil.isBoolean(fieldType); @@ -203,24 +201,19 @@ public class BeanDesc implements Serializable { Method getter = null; Method setter = null; String methodName; - Class[] parameterTypes; - for (Method method : methods) { - parameterTypes = method.getParameterTypes(); - if (parameterTypes.length > 1) { - // 多于1个参数说明非Getter或Setter - continue; - } - + for (Method method : gettersOrSetters) { methodName = method.getName(); - if (parameterTypes.length == 0) { + if (method.getParameterCount() == 0) { // 无参数,可能为Getter方法 if (isMatchGetter(methodName, fieldName, isBooleanField, ignoreCase)) { // 方法名与字段名匹配,则为Getter方法 getter = method; } } else if (isMatchSetter(methodName, fieldName, isBooleanField, ignoreCase)) { - // 只有一个参数的情况下方法名与字段名对应匹配,则为Setter方法 - setter = method; + // setter方法的参数类型和字段类型必须一致,或参数类型是字段类型的子类 + if(fieldType.isAssignableFrom(method.getParameterTypes()[0])){ + setter = method; + } } if (null != getter && null != setter) { // 如果Getter和Setter方法都找到了,不再继续寻找 @@ -261,15 +254,6 @@ public class BeanDesc implements Serializable { handledFieldName = StrUtil.upperFirst(fieldName); } - if (false == methodName.startsWith("get") && false == methodName.startsWith("is")) { - // 非标准Getter方法 - return false; - } - if ("getclass".equals(methodName)) { - //跳过getClass方法 - return false; - } - // 针对Boolean类型特殊检查 if (isBooleanField) { if (fieldName.startsWith("is")) { diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java b/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java index 796124648..d9452cd14 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java @@ -88,9 +88,8 @@ public class BeanUtil { */ public static boolean hasSetter(Class clazz) { if (ClassUtil.isNormalClass(clazz)) { - final Method[] methods = clazz.getMethods(); - for (Method method : methods) { - if (method.getParameterTypes().length == 1 && method.getName().startsWith("set")) { + for (Method method : clazz.getMethods()) { + if (method.getParameterCount() == 1 && method.getName().startsWith("set")) { // 检测包含标准的setXXX方法即视为标准的JavaBean return true; } @@ -110,7 +109,7 @@ public class BeanUtil { public static boolean hasGetter(Class clazz) { if (ClassUtil.isNormalClass(clazz)) { for (Method method : clazz.getMethods()) { - if (method.getParameterTypes().length == 0) { + if (method.getParameterCount() == 0) { if (method.getName().startsWith("get") || method.getName().startsWith("is")) { return true; } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/reflect/MethodHandleUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/MethodHandleUtil.java index 781208744..fbfa2ded3 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/reflect/MethodHandleUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/MethodHandleUtil.java @@ -12,6 +12,7 @@ import java.lang.reflect.Method; /** * 方法句柄{@link MethodHandle}封装工具类
+ * 方法句柄是一个有类型的,可以直接执行的指向底层方法、构造器、field等的引用,可以简单理解为函数指针,它是一种更加底层的查找、调整和调用方法的机制。 * 参考: *