From aba35cc6c2704e73368f66b97dc1dc9141c86f11 Mon Sep 17 00:00:00 2001 From: emptypoint <1215582715@qq.com> Date: Sun, 18 Sep 2022 12:49:01 +0800 Subject: [PATCH 01/73] =?UTF-8?q?predicate.test=E7=9A=84=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E4=B8=8D=E8=83=BD=E4=B8=BAnull;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/EasyStream.java | 7 ++----- .../test/java/cn/hutool/core/stream/EasyStreamTest.java | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 90de48122..6a497ea33 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -313,11 +313,8 @@ public class EasyStream extends AbstractEnhancedWrappedStream parentPredicate) { Objects.requireNonNull(parentPredicate); final List list = toList(); - final List parents = EasyStream.of(list).filter(e -> - // 此处是为了适配 parentPredicate.test空指针 情况 - // 因为Predicate.test的返回值是boolean,所以如果 e -> null 这种返回null的情况,会直接抛出NPE - Opt.ofTry(() -> parentPredicate.test(e)).filter(Boolean::booleanValue).isPresent()) - .toList(); + // 根节点列表 + final List parents = EasyStream.of(list).filter(parentPredicate).toList(); return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, EasyStream.of(list).group(pIdGetter), parents); } diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java index 26fa81ef8..c8a810fb9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java @@ -476,7 +476,7 @@ public class EasyStreamTest { Student.builder().id(8L).name("jobob").parentId(5L).build() ) // just 4 lambda ,top by condition - .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent); + .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::isMatchParent); Assert.assertEquals(asList( Student.builder().id(1L).name("dromara").matchParent(true) .children(asList(Student.builder().id(3L).name("hutool").parentId(1L) @@ -540,7 +540,7 @@ public class EasyStreamTest { private Long id; private Long parentId; private List children; - private Boolean matchParent = false; + private boolean matchParent; @Tolerate public Student() { From 9417bbee2e5b5448953e2dc6956160d53bd66a5d Mon Sep 17 00:00:00 2001 From: emptypoint <1215582715@qq.com> Date: Sun, 18 Sep 2022 20:04:46 +0800 Subject: [PATCH 02/73] =?UTF-8?q?=E8=A7=84=E8=8C=83Test=E4=B8=ADPOJO?= =?UTF-8?q?=E7=9A=84=E4=BD=BF=E7=94=A8;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/java/cn/hutool/core/stream/EasyStreamTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java index c8a810fb9..9ea222491 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java @@ -2,6 +2,7 @@ package cn.hutool.core.stream; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.BooleanUtil; import lombok.Data; import lombok.experimental.Tolerate; import org.junit.Assert; @@ -476,7 +477,7 @@ public class EasyStreamTest { Student.builder().id(8L).name("jobob").parentId(5L).build() ) // just 4 lambda ,top by condition - .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::isMatchParent); + .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent); Assert.assertEquals(asList( Student.builder().id(1L).name("dromara").matchParent(true) .children(asList(Student.builder().id(3L).name("hutool").parentId(1L) @@ -540,12 +541,16 @@ public class EasyStreamTest { private Long id; private Long parentId; private List children; - private boolean matchParent; + private Boolean matchParent; @Tolerate public Student() { // this is an accessible parameterless constructor. } + + public Boolean getMatchParent() { + return BooleanUtil.isTrue(matchParent); + } } @Test From 28f6a76933d03fb810294f5a68deb2991612c087 Mon Sep 17 00:00:00 2001 From: emptypoint <1215582715@qq.com> Date: Sun, 18 Sep 2022 20:54:33 +0800 Subject: [PATCH 03/73] =?UTF-8?q?=E4=BC=98=E5=8C=96toTree=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=BE=AA=E7=8E=AF=E4=BB=A3=E6=9B=BF=E9=80=92=E5=BD=92;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/EasyStream.java | 62 +++++++------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 6a497ea33..5bcf148c2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -1,7 +1,7 @@ package cn.hutool.core.stream; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Opt; -import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; @@ -267,7 +267,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream将集合转换为树,默认用 {@code parentId == null} 作为顶部,内置一个小递归 + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -285,12 +285,13 @@ public class EasyStream extends AbstractEnhancedWrappedStream idGetter, final Function pIdGetter, final BiConsumer> childrenSetter) { - final Map> pIdValuesMap = group(pIdGetter); - return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, pIdValuesMap, pIdValuesMap.get(null)); + // 使用 parentId == null 判断是否为根节点 + final Predicate parentPredicate = node -> null == pIdGetter.apply(node); + return toTree(idGetter, pIdGetter, childrenSetter, parentPredicate); } /** - * 将集合转换为树,自定义树顶部的判断条件,内置一个小递归(没错,lambda可以写递归) + * 将集合转换为树,自定义根节点的判断条件 * 因为需要在当前传入数据里查找,所以这是一个结束操作 * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -305,46 +306,31 @@ public class EasyStream extends AbstractEnhancedWrappedStream */ - public > List toTree( final Function idGetter, final Function pIdGetter, final BiConsumer> childrenSetter, final Predicate parentPredicate) { - Objects.requireNonNull(parentPredicate); - final List list = toList(); - // 根节点列表 - final List parents = EasyStream.of(list).filter(parentPredicate).toList(); - return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, EasyStream.of(list).group(pIdGetter), parents); - } - - /** - * toTree的内联函数,内置一个小递归(没错,lambda可以写递归) - * 因为需要在当前传入数据里查找,所以这是一个结束操作 - * - * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} - * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} - * @param pIdValuesMap parentId和值组成的map,用来降低复杂度 - * @param parents 顶部数据 - * @param 此处是id的泛型限制 - * @return list 组装好的树 - */ - private > List getChildrenFromMapByPidAndSet( - final Function idGetter, - final BiConsumer> childrenSetter, - final Map> pIdValuesMap, - final List parents) { Objects.requireNonNull(idGetter); + Objects.requireNonNull(pIdGetter); Objects.requireNonNull(childrenSetter); - Objects.requireNonNull(pIdValuesMap); - final MutableObj>> recursiveRef = new MutableObj<>(); - final Consumer> recursive = values -> EasyStream.of(values, isParallel()).forEach(value -> { - final List children = pIdValuesMap.get(idGetter.apply(value)); - childrenSetter.accept(value, children); - recursiveRef.get().accept(children); - }); - recursiveRef.set(recursive); - recursive.accept(parents); + Objects.requireNonNull(parentPredicate); + + List nodeList = toList(); + // 父id 关联的 子节点列表 + final Map> pId2ChildrenMap = of(nodeList).group(pIdGetter); + List parents = ListUtil.of(); + + for (T node : nodeList) { + if (parentPredicate.test(node)) { + parents.add(node); + } + // 设置 该节点的子节点列表 + final List children = pId2ChildrenMap.get(idGetter.apply(node)); + if (children != null) { + childrenSetter.accept(node, children); + } + } return parents; } From 03a25799840bb039cfd6646d0571fd821173a820 Mon Sep 17 00:00:00 2001 From: emptypoint <1215582715@qq.com> Date: Sun, 18 Sep 2022 21:07:15 +0800 Subject: [PATCH 04/73] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=B9=B6=E8=A1=8C?= =?UTF-8?q?=E6=B5=81=EF=BC=8C=E6=8F=90=E9=AB=98=E5=A4=A7=E9=87=8F=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=9C=BA=E6=99=AF=E4=B8=8B=E7=9A=84=E6=80=A7=E8=83=BD?= =?UTF-8?q?;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/EasyStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 5bcf148c2..b100d14f1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -321,7 +321,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream> pId2ChildrenMap = of(nodeList).group(pIdGetter); List parents = ListUtil.of(); - for (T node : nodeList) { + of(nodeList, true).forEach(node -> { if (parentPredicate.test(node)) { parents.add(node); } @@ -330,7 +330,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream Date: Sun, 18 Sep 2022 22:46:25 +0800 Subject: [PATCH 05/73] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A0=B9=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E4=B8=BAnull=E6=97=B6=E7=9A=84=E5=9C=BA=E6=99=AF;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/EasyStream.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index b100d14f1..bbda79b8c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -1,10 +1,10 @@ package cn.hutool.core.stream; -import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Opt; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -317,21 +317,27 @@ public class EasyStream extends AbstractEnhancedWrappedStream nodeList = toList(); + // 根据 父id 分组,让key为null的组中全是根节点 + final Function pIdClassifier = node -> { + R parentId = pIdGetter.apply(node); + // 父id为null(另类的根节点),或者是根节点 + if (parentId == null || parentPredicate.test(node)) { + return null; + } + return parentId; + }; // 父id 关联的 子节点列表 - final Map> pId2ChildrenMap = of(nodeList).group(pIdGetter); - List parents = ListUtil.of(); + final Map> pId2ChildrenMap = of(nodeList).group(pIdClassifier); of(nodeList, true).forEach(node -> { - if (parentPredicate.test(node)) { - parents.add(node); - } // 设置 该节点的子节点列表 final List children = pId2ChildrenMap.get(idGetter.apply(node)); if (children != null) { childrenSetter.accept(node, children); } }); - return parents; + // 返回根节点列表 + return pId2ChildrenMap.getOrDefault(null, Collections.emptyList()); } /** From df748856d7475dfabf684658cbdd1064366036c2 Mon Sep 17 00:00:00 2001 From: Zjp <1215582715@qq.com> Date: Mon, 19 Sep 2022 09:01:12 +0800 Subject: [PATCH 06/73] =?UTF-8?q?=E5=87=8F=E5=B0=91=E9=A2=9D=E5=A4=96?= =?UTF-8?q?=E7=9A=84=E5=88=A4=E6=96=AD;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/EasyStream.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index bbda79b8c..f2af24e8b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -319,12 +319,12 @@ public class EasyStream extends AbstractEnhancedWrappedStream nodeList = toList(); // 根据 父id 分组,让key为null的组中全是根节点 final Function pIdClassifier = node -> { - R parentId = pIdGetter.apply(node); - // 父id为null(另类的根节点),或者是根节点 - if (parentId == null || parentPredicate.test(node)) { + // 该节点是根节点, 分到 父id 为null的组中 + if (parentPredicate.test(node)) { return null; } - return parentId; + // 返回 父id + return pIdGetter.apply(node); }; // 父id 关联的 子节点列表 final Map> pId2ChildrenMap = of(nodeList).group(pIdClassifier); From 41ce120da56a05706c548b3f201209ddc9c46b7f Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:16:27 +0800 Subject: [PATCH 07/73] =?UTF-8?q?:trollface:=20=E4=BC=98=E5=8C=96toTree?= =?UTF-8?q?=E6=80=A7=E8=83=BD=EF=BC=8C=E6=8A=BD=E5=8F=96=E5=88=B0Collector?= =?UTF-8?q?Util=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/CollectorUtil.java | 133 +++++++++++++++++- .../cn/hutool/core/stream/EasyStream.java | 54 ++----- .../cn/hutool/core/stream/EasyStreamTest.java | 8 +- 3 files changed, 144 insertions(+), 51 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 14ffe6b6c..9b9e483dc 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -1,14 +1,12 @@ package cn.hutool.core.stream; import cn.hutool.core.lang.Opt; +import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; +import java.util.function.*; import java.util.stream.Collector; import java.util.stream.Collectors; @@ -371,4 +369,131 @@ public class CollectorUtil { public static Collector, ?, Map> entryToMap() { return toMap(Map.Entry::getKey, Map.Entry::getValue); } + + /** + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点,内置一个递归,注意内存开销 + * 因为需要在当前传入数据里查找,所以这是一个结束操作
+ * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} + * @param isParallel 是否并行去组装,数据量特别大时使用 + * @param 此处是元素类型 + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *

{@code
+	 * List studentTree = students.stream().collect(toTree(Student::getId, Student::getParentId, Student::setChildren, isParallel));
+	 * }
+ */ + public static , T> Collector> toTree( + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter, + final boolean isParallel) { + return toTree(idGetter, pIdGetter, null, childrenSetter, isParallel); + } + + /** + *

将集合转换为树,默认用 {@code parentId == pidValue} 来判断树的根节点,可以为null,内置一个递归,注意内存开销 + * 因为需要在当前传入数据里查找,所以这是一个结束操作
+ * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} + * @param isParallel 是否并行去组装,数据量特别大时使用 + * @param 此处是元素类型 + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *

{@code
+	 * List studentTree = students.stream().collect(toTree(Student::getId, Student::getParentId, 0L, Student::setChildren, isParallel));
+	 * }
+ * @author VampireAchao + */ + public static , T> Collector> toTree( + final Function idGetter, + final Function pIdGetter, + final R pidValue, + final BiConsumer> childrenSetter, + final boolean isParallel) { + return Collectors.collectingAndThen(groupingBy(pIdGetter, Collectors.toList()), + getChildrenFromMapByPidAndSet(idGetter, pIdValuesMap -> pIdValuesMap.get(pidValue), childrenSetter, isParallel)); + } + + /** + * 将集合转换为树,自定义根节点的判断条件,内置一个递归,注意内存开销 + * 因为需要在当前传入数据里查找,所以这是一个结束操作 + * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} + * @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) } + * @param 此处是元素类型 + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *
{@code
+	 * List studentTree = EasyStream.of(students).
+	 * 	.toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
+	 * }
+ * @author VampireAchao + */ + public static , T> Collector> toTree( + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter, + final Predicate parentPredicate, + boolean isParallel) { + List parents = new ArrayList<>(); + return Collectors.collectingAndThen(groupingBy(pIdGetter, + new SimpleCollector<>(ArrayList::new, + (acc, e) -> { + if (parentPredicate.test(e)) { + parents.add(e); + } + acc.add(e); + }, + (left, right) -> { + left.addAll(right); + return left; + }, + CH_ID)), + getChildrenFromMapByPidAndSet(idGetter, pIdValuesMap -> parents, childrenSetter, isParallel)); + } + + /** + * toTree的内联函数,内置一个小递归(没错,lambda可以写递归) + * 因为需要在当前传入数据里查找,所以这是一个结束操作 + * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param parentFactory 顶部数据工厂方法 + * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} + * @param isParallel 是否并行处理 + * @param 此处是元素类型 + * @param 此处是id的泛型限制 + * @return list 组装好的树 + * @author VampireAchao + */ + private static , T> Function>, List> getChildrenFromMapByPidAndSet( + final Function idGetter, + final Function>, List> parentFactory, + final BiConsumer> childrenSetter, + boolean isParallel) { + return pIdValuesMap -> { + final MutableObj>> recursiveRef = new MutableObj<>(); + final Consumer> recursive = parents -> EasyStream.of(parents, isParallel).forEach(parent -> { + final List children = pIdValuesMap.get(idGetter.apply(parent)); + childrenSetter.accept(parent, children); + recursiveRef.get().accept(children); + }); + List parents = parentFactory.apply(pIdValuesMap); + if (!parents.isEmpty()) { + recursiveRef.set(recursive); + recursiveRef.get().accept(parents); + } + return parents; + }; + } + } diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index f2af24e8b..9b77b1cf5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -4,9 +4,7 @@ import cn.hutool.core.lang.Opt; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Spliterator; import java.util.function.*; @@ -267,7 +265,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点,内置一个递归,注意内存开销 * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -280,18 +278,17 @@ public class EasyStream extends AbstractEnhancedWrappedStream studentTree = EasyStream.of(students). * toTree(Student::getId, Student::getParentId, Student::setChildren); * } + * @author VampireAchao */ public > List toTree( - final Function idGetter, - final Function pIdGetter, - final BiConsumer> childrenSetter) { - // 使用 parentId == null 判断是否为根节点 - final Predicate parentPredicate = node -> null == pIdGetter.apply(node); - return toTree(idGetter, pIdGetter, childrenSetter, parentPredicate); + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter) { + return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, isParallel())); } /** - * 将集合转换为树,自定义根节点的判断条件 + * 将集合转换为树,自定义根节点的判断条件,内置一个递归,注意内存开销 * 因为需要在当前传入数据里查找,所以这是一个结束操作 * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -305,39 +302,14 @@ public class EasyStream extends AbstractEnhancedWrappedStream studentTree = EasyStream.of(students). * .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent); * } + * @author VampireAchao */ public > List toTree( - final Function idGetter, - final Function pIdGetter, - final BiConsumer> childrenSetter, - final Predicate parentPredicate) { - Objects.requireNonNull(idGetter); - Objects.requireNonNull(pIdGetter); - Objects.requireNonNull(childrenSetter); - Objects.requireNonNull(parentPredicate); - - List nodeList = toList(); - // 根据 父id 分组,让key为null的组中全是根节点 - final Function pIdClassifier = node -> { - // 该节点是根节点, 分到 父id 为null的组中 - if (parentPredicate.test(node)) { - return null; - } - // 返回 父id - return pIdGetter.apply(node); - }; - // 父id 关联的 子节点列表 - final Map> pId2ChildrenMap = of(nodeList).group(pIdClassifier); - - of(nodeList, true).forEach(node -> { - // 设置 该节点的子节点列表 - final List children = pId2ChildrenMap.get(idGetter.apply(node)); - if (children != null) { - childrenSetter.accept(node, children); - } - }); - // 返回根节点列表 - return pId2ChildrenMap.getOrDefault(null, Collections.emptyList()); + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter, + final Predicate parentPredicate) { + return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, parentPredicate, isParallel())); } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java index 9ea222491..166a3f201 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java @@ -182,7 +182,7 @@ public class EasyStreamTest { Assert.assertEquals(collect2, distinctBy2); Assert.assertEquals( - 4, EasyStream.of(1, 2, 2, null, 3, null).parallel(true).distinct(t -> Objects.isNull(t) ? null : t.toString()).sequential().count() + 4, EasyStream.of(1, 2, 2, null, 3, null).parallel(true).distinct(t -> Objects.isNull(t) ? null : t.toString()).sequential().count() ); } @@ -477,7 +477,7 @@ public class EasyStreamTest { Student.builder().id(8L).name("jobob").parentId(5L).build() ) // just 4 lambda ,top by condition - .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent); + .toTree(Student::getId, Student::getParentId, Student::setChildren, s -> BooleanUtil.isTrue(s.getMatchParent())); Assert.assertEquals(asList( Student.builder().id(1L).name("dromara").matchParent(true) .children(asList(Student.builder().id(3L).name("hutool").parentId(1L) @@ -547,10 +547,6 @@ public class EasyStreamTest { public Student() { // this is an accessible parameterless constructor. } - - public Boolean getMatchParent() { - return BooleanUtil.isTrue(matchParent); - } } @Test From 9354d1c74aa342877f0e64762927f7e1bd3b3300 Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:28:09 +0800 Subject: [PATCH 08/73] =?UTF-8?q?:trollface:=20=E6=BC=8F=E6=8E=89=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AAfinal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 9b9e483dc..4816b27d3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -444,7 +444,7 @@ public class CollectorUtil { final Function pIdGetter, final BiConsumer> childrenSetter, final Predicate parentPredicate, - boolean isParallel) { + final boolean isParallel) { List parents = new ArrayList<>(); return Collectors.collectingAndThen(groupingBy(pIdGetter, new SimpleCollector<>(ArrayList::new, @@ -479,7 +479,7 @@ public class CollectorUtil { final Function idGetter, final Function>, List> parentFactory, final BiConsumer> childrenSetter, - boolean isParallel) { + final boolean isParallel) { return pIdValuesMap -> { final MutableObj>> recursiveRef = new MutableObj<>(); final Consumer> recursive = parents -> EasyStream.of(parents, isParallel).forEach(parent -> { From 1f6a651fefaf09134df25a545a8c5ab26cb9649b Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:31:25 +0800 Subject: [PATCH 09/73] =?UTF-8?q?:trollface:=20=E6=BC=8F=E6=8E=89=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AAfinal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 4816b27d3..193a18645 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -445,7 +445,7 @@ public class CollectorUtil { final BiConsumer> childrenSetter, final Predicate parentPredicate, final boolean isParallel) { - List parents = new ArrayList<>(); + final List parents = new ArrayList<>(); return Collectors.collectingAndThen(groupingBy(pIdGetter, new SimpleCollector<>(ArrayList::new, (acc, e) -> { From d9d3c39d4e5058c08fb0638bf87806273e39957f Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:31:39 +0800 Subject: [PATCH 10/73] =?UTF-8?q?:trollface:=20=E6=BC=8F=E6=8E=89=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AAfinal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 193a18645..29c485a49 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -487,7 +487,7 @@ public class CollectorUtil { childrenSetter.accept(parent, children); recursiveRef.get().accept(children); }); - List parents = parentFactory.apply(pIdValuesMap); + final List parents = parentFactory.apply(pIdValuesMap); if (!parents.isEmpty()) { recursiveRef.set(recursive); recursiveRef.get().accept(parents); From e81585d7d0b845bc837ba1c7a9213b31537701de Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:50:18 +0800 Subject: [PATCH 11/73] :trollface: false --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 29c485a49..35d3ecc8c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -488,7 +488,7 @@ public class CollectorUtil { recursiveRef.get().accept(children); }); final List parents = parentFactory.apply(pIdValuesMap); - if (!parents.isEmpty()) { + if (false == parents.isEmpty()) { recursiveRef.set(recursive); recursiveRef.get().accept(parents); } From 0dda333b07f5464577276ff8762ee780b19b1ac6 Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:53:58 +0800 Subject: [PATCH 12/73] =?UTF-8?q?:trollface:=20=E9=80=92=E5=BD=92=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E9=81=8D=E5=8E=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/CollectorUtil.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 35d3ecc8c..e2b3e1f9d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -1,7 +1,6 @@ package cn.hutool.core.stream; import cn.hutool.core.lang.Opt; -import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; @@ -481,18 +480,14 @@ public class CollectorUtil { final BiConsumer> childrenSetter, final boolean isParallel) { return pIdValuesMap -> { - final MutableObj>> recursiveRef = new MutableObj<>(); - final Consumer> recursive = parents -> EasyStream.of(parents, isParallel).forEach(parent -> { - final List children = pIdValuesMap.get(idGetter.apply(parent)); - childrenSetter.accept(parent, children); - recursiveRef.get().accept(children); - }); - final List parents = parentFactory.apply(pIdValuesMap); - if (false == parents.isEmpty()) { - recursiveRef.set(recursive); - recursiveRef.get().accept(parents); - } - return parents; + EasyStream.of(pIdValuesMap.values(), isParallel).flat(Function.identity()) + .forEach(value -> { + final List children = pIdValuesMap.get(idGetter.apply(value)); + if (children != null) { + childrenSetter.accept(value, children); + } + }); + return parentFactory.apply(pIdValuesMap); }; } From c4e20d91849e4fc8e6df3b977d28710c6b0f206d Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:55:53 +0800 Subject: [PATCH 13/73] =?UTF-8?q?:trollface:=20=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/hutool/core/stream/CollectorUtil.java | 8 ++++---- .../src/main/java/cn/hutool/core/stream/EasyStream.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index e2b3e1f9d..b6b7c158c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -370,7 +370,7 @@ public class CollectorUtil { } /** - *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点,内置一个递归,注意内存开销 + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -394,7 +394,7 @@ public class CollectorUtil { } /** - *

将集合转换为树,默认用 {@code parentId == pidValue} 来判断树的根节点,可以为null,内置一个递归,注意内存开销 + *

将集合转换为树,默认用 {@code parentId == pidValue} 来判断树的根节点,可以为null * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -421,7 +421,7 @@ public class CollectorUtil { } /** - * 将集合转换为树,自定义根节点的判断条件,内置一个递归,注意内存开销 + * 将集合转换为树,自定义根节点的判断条件 * 因为需要在当前传入数据里查找,所以这是一个结束操作 * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -462,7 +462,7 @@ public class CollectorUtil { } /** - * toTree的内联函数,内置一个小递归(没错,lambda可以写递归) + * toTree的内联函数 * 因为需要在当前传入数据里查找,所以这是一个结束操作 * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 9b77b1cf5..1fea0642d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -265,7 +265,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点,内置一个递归,注意内存开销 + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -288,7 +288,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream Date: Mon, 19 Sep 2022 11:56:52 +0800 Subject: [PATCH 14/73] :trollface: javadoc --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index b6b7c158c..d318bd852 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -399,6 +399,7 @@ public class CollectorUtil { * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param pidValue pid的值 * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} * @param isParallel 是否并行去组装,数据量特别大时使用 * @param 此处是元素类型 @@ -428,6 +429,7 @@ public class CollectorUtil { * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} * @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) } + * @param isParallel 是否并行处理 * @param 此处是元素类型 * @param 此处是id、parentId的泛型限制 * @return list 组装好的树
From e924b77fb8ad3f4c03a199864618f7230dd49dc2 Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Tue, 20 Sep 2022 09:58:05 +0800 Subject: [PATCH 15/73] =?UTF-8?q?:trollface:=20=E6=8A=BD=E5=8F=96=E5=88=B0?= =?UTF-8?q?TerminableWrappedStream=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/CollectorUtil.java | 4 +- .../cn/hutool/core/stream/EasyStream.java | 48 --- .../core/stream/TerminableWrappedStream.java | 351 ++++++++++-------- 3 files changed, 203 insertions(+), 200 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index d318bd852..1dcc72096 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -453,7 +453,9 @@ public class CollectorUtil { if (parentPredicate.test(e)) { parents.add(e); } - acc.add(e); + if (idGetter.apply(e) != null) { + acc.add(e); + } }, (left, right) -> { left.addAll(right); diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 1fea0642d..b892b7199 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -264,54 +264,6 @@ public class EasyStream extends AbstractEnhancedWrappedStream(stream); } - /** - *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 - * 因为需要在当前传入数据里查找,所以这是一个结束操作
- * - * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} - * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} - * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} - * @param 此处是id、parentId的泛型限制 - * @return list 组装好的树
- * eg: - *

{@code
-	 * List studentTree = EasyStream.of(students).
-	 * 	toTree(Student::getId, Student::getParentId, Student::setChildren);
-	 * }
- * @author VampireAchao - */ - public > List toTree( - final Function idGetter, - final Function pIdGetter, - final BiConsumer> childrenSetter) { - return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, isParallel())); - } - - /** - * 将集合转换为树,自定义根节点的判断条件 - * 因为需要在当前传入数据里查找,所以这是一个结束操作 - * - * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} - * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} - * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} - * @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) } - * @param 此处是id、parentId的泛型限制 - * @return list 组装好的树
- * eg: - *
{@code
-	 * List studentTree = EasyStream.of(students).
-	 * 	.toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
-	 * }
- * @author VampireAchao - */ - public > List toTree( - final Function idGetter, - final Function pIdGetter, - final BiConsumer> childrenSetter, - final Predicate parentPredicate) { - return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, parentPredicate, isParallel())); - } - /** * 建造者 * diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/TerminableWrappedStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/TerminableWrappedStream.java index e329f9901..19958f0c4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/TerminableWrappedStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/TerminableWrappedStream.java @@ -22,47 +22,47 @@ import java.util.stream.Stream; */ public interface TerminableWrappedStream> extends WrappedStream { - // region ============ to collection ============ + // region ============ to collection ============ - /** - * 转换为{@link ArrayList} - * - * @return 集合 - * @see #toColl(Supplier) - */ - default List toList() { - return this.toColl(ArrayList::new); - } - - /** - * 换为不可变集合 - * - * @return 集合 + /** + * 转换为{@link ArrayList} + * + * @return 集合 * @see #toColl(Supplier) */ - default List toUnmodifiableList() { - return Collections.unmodifiableList(this.toList()); - } + default List toList() { + return this.toColl(ArrayList::new); + } - /** - * 转换为HashSet - * - * @return 集合 + /** + * 换为不可变集合 + * + * @return 集合 * @see #toColl(Supplier) */ - default Set toSet() { - return this.toColl(HashSet::new); - } + default List toUnmodifiableList() { + return Collections.unmodifiableList(this.toList()); + } - /** - * 换为不可变集合 - * - * @return 集合 + /** + * 转换为HashSet + * + * @return 集合 * @see #toColl(Supplier) */ - default Set toUnmodifiableSet() { - return Collections.unmodifiableSet(this.toSet()); - } + default Set toSet() { + return this.toColl(HashSet::new); + } + + /** + * 换为不可变集合 + * + * @return 集合 + * @see #toColl(Supplier) + */ + default Set toUnmodifiableSet() { + return Collections.unmodifiableSet(this.toSet()); + } /** * 转换成集合 @@ -76,103 +76,103 @@ public interface TerminableWrappedStream key类型 - * @return map + /** + * 转换为map,key为给定操作执行后的返回值,value为当前元素 + * + * @param keyMapper 指定的key操作 + * @param key类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toMap(final Function keyMapper) { - return this.toMap(keyMapper, Function.identity()); - } + */ + default Map toMap(final Function keyMapper) { + return this.toMap(keyMapper, Function.identity()); + } - /** - * 转换为map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param key类型 - * @param value类型 - * @return map + /** + * 转换为map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param key类型 + * @param value类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toMap( - final Function keyMapper, final Function valueMapper) { - return this.toMap(keyMapper, valueMapper, (l, r) -> r); - } + */ + default Map toMap( + final Function keyMapper, final Function valueMapper) { + return this.toMap(keyMapper, valueMapper, (l, r) -> r); + } - /** - * 转换为不可变map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param key类型 - * @param value类型 - * @return map + /** + * 转换为不可变map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param key类型 + * @param value类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toUnmodifiableMap( - final Function keyMapper, final Function valueMapper) { - return Collections.unmodifiableMap(this.toMap(keyMapper, valueMapper)); - } + */ + default Map toUnmodifiableMap( + final Function keyMapper, final Function valueMapper) { + return Collections.unmodifiableMap(this.toMap(keyMapper, valueMapper)); + } - /** - * 转换为map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param mergeFunction 合并操作 - * @param key类型 - * @param value类型 - * @return map + /** + * 转换为map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param mergeFunction 合并操作 + * @param key类型 + * @param value类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toMap( - final Function keyMapper, - final Function valueMapper, - final BinaryOperator mergeFunction) { - return this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); - } + */ + default Map toMap( + final Function keyMapper, + final Function valueMapper, + final BinaryOperator mergeFunction) { + return this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); + } - /** - * 转换为不可变map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param mergeFunction 合并操作 - * @param key类型 - * @param value类型 - * @return map + /** + * 转换为不可变map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param mergeFunction 合并操作 + * @param key类型 + * @param value类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toUnmodifiableMap( - final Function keyMapper, - final Function valueMapper, - final BinaryOperator mergeFunction) { - return Collections.unmodifiableMap( - this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new) + */ + default Map toUnmodifiableMap( + final Function keyMapper, + final Function valueMapper, + final BinaryOperator mergeFunction) { + return Collections.unmodifiableMap( + this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new) ); - } + } - /** - * 转换为map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param mergeFunction 合并操作 - * @param mapSupplier map工厂 - * @param key类型 - * @param value类型 - * @param map类型 - * @return map - */ - default > M toMap( + /** + * 转换为map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param mergeFunction 合并操作 + * @param mapSupplier map工厂 + * @param key类型 + * @param value类型 + * @param map类型 + * @return map + */ + default > M toMap( final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, @@ -181,40 +181,89 @@ public interface TerminableWrappedStream将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 + * 因为需要在当前传入数据里查找,所以这是一个结束操作
+ * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *
{@code
+	 * List studentTree = EasyStream.of(students).
+	 * 	toTree(Student::getId, Student::getParentId, Student::setChildren);
+	 * }
+ * @author VampireAchao + */ + default > List toTree( + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter) { + return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, isParallel())); + } - // region ============ to zip ============ + /** + * 将集合转换为树,自定义根节点的判断条件 + * 因为需要在当前传入数据里查找,所以这是一个结束操作 + * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} + * @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) } + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *
{@code
+	 * List studentTree = EasyStream.of(students).
+	 * 	.toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
+	 * }
+ * @author VampireAchao + */ + default > List toTree( + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter, + final Predicate parentPredicate) { + return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, parentPredicate, isParallel())); + } - /** - * 与给定的可迭代对象转换成map,key为现有元素,value为给定可迭代对象迭代的元素
- * 至少包含全部的key,如果对应位置上的value不存在,则为null - * - * @param other 可迭代对象 - * @param 可迭代对象迭代的元素类型 - * @return map,key为现有元素,value为给定可迭代对象迭代的元素;
- * 至少包含全部的key,如果对应位置上的value不存在,则为null;
- * 如果key重复, 则保留最后一个关联的value;
- */ - default Map toZip(final Iterable other) { + + // endregion + + // region ============ to zip ============ + + /** + * 与给定的可迭代对象转换成map,key为现有元素,value为给定可迭代对象迭代的元素
+ * 至少包含全部的key,如果对应位置上的value不存在,则为null + * + * @param other 可迭代对象 + * @param 可迭代对象迭代的元素类型 + * @return map,key为现有元素,value为给定可迭代对象迭代的元素;
+ * 至少包含全部的key,如果对应位置上的value不存在,则为null;
+ * 如果key重复, 则保留最后一个关联的value;
+ */ + default Map toZip(final Iterable other) { Objects.requireNonNull(other); - // value对象迭代器 - final Iterator iterator = Opt.ofNullable(other).map(Iterable::iterator).orElseGet(Collections::emptyIterator); - if (this.isParallel()) { + // value对象迭代器 + final Iterator iterator = Opt.ofNullable(other).map(Iterable::iterator).orElseGet(Collections::emptyIterator); + if (this.isParallel()) { final List keyList = toList(); - final Map map = new HashMap<>(keyList.size()); - for (final T key : keyList) { - map.put(key, iterator.hasNext() ? iterator.next() : null); - } - return map; - } else { - return this.toMap(Function.identity(), e -> iterator.hasNext() ? iterator.next() : null); - } - } + final Map map = new HashMap<>(keyList.size()); + for (final T key : keyList) { + map.put(key, iterator.hasNext() ? iterator.next() : null); + } + return map; + } else { + return this.toMap(Function.identity(), e -> iterator.hasNext() ? iterator.next() : null); + } + } - // endregion + // endregion // region ============ to optional ============ @@ -408,7 +457,7 @@ public interface TerminableWrappedStream Map group( - final Function classifier, final Collector downstream) { + final Function classifier, final Collector downstream) { return this.group(classifier, HashMap::new, downstream); } @@ -426,9 +475,9 @@ public interface TerminableWrappedStream> M group( - final Function classifier, - final Supplier mapFactory, - final Collector downstream) { + final Function classifier, + final Supplier mapFactory, + final Collector downstream) { Objects.requireNonNull(classifier); Objects.requireNonNull(mapFactory); Objects.requireNonNull(downstream); @@ -449,8 +498,8 @@ public interface TerminableWrappedStream 值类型 - * @param predicate 判断条件 + * @param 值类型 + * @param predicate 判断条件 * @param collFactory 提供的集合 * @return map * @see #partition(Predicate, Collector) @@ -464,7 +513,7 @@ public interface TerminableWrappedStream 返回值类型 + * @param 返回值类型 * @return map */ default Map partition(final Predicate predicate, final Collector downstream) { From 463539f826903a3b164a50613c73d2307853e21f Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Tue, 20 Sep 2022 10:14:37 +0800 Subject: [PATCH 16/73] =?UTF-8?q?:trollface:=20=E8=B0=83=E6=95=B4=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stream/AbstractEnhancedWrappedStreamTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java index 8935a75ad..be03d08bd 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java @@ -40,7 +40,7 @@ public class AbstractEnhancedWrappedStreamTest { @Test public void testToSet() { final List list = asList(1, 2, 3); - Set toSet = wrap(list).map(String::valueOf).toSet(); + final Set toSet = wrap(list).map(String::valueOf).toSet(); Assert.assertEquals(new HashSet<>(asList("1", "2", "3")), toSet); } @@ -636,7 +636,7 @@ public class AbstractEnhancedWrappedStreamTest { List zip = wrap(orders).zip(list, (e1, e2) -> e1 + "." + e2).toList(); Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip); - zip = wrap((Stream) EasyStream.iterate(1, i -> i + 1)).limit(10).zip(list, (e1, e2) -> e1 + "." + e2).toList(); + zip = this.wrap((Stream)EasyStream.iterate(1, i -> i + 1)).limit(10).zip(list, (e1, e2) -> e1 + "." + e2).toList(); Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip); } @@ -663,15 +663,15 @@ public class AbstractEnhancedWrappedStreamTest { } @SafeVarargs - private static Wrapper wrap(T... array) { + private final Wrapper wrap(final T... array) { return new Wrapper<>(Stream.of(array)); } - private static Wrapper wrap(Iterable iterable) { + private Wrapper wrap(final Iterable iterable) { return new Wrapper<>(StreamSupport.stream(iterable.spliterator(), false)); } - private static Wrapper wrap(Stream stream) { + private Wrapper wrap(final Stream stream) { return new Wrapper<>(stream); } @@ -683,12 +683,12 @@ public class AbstractEnhancedWrappedStreamTest { * @param stream 包装的流对象 * @throws NullPointerException 当{@code unwrap}为{@code null}时抛出 */ - protected Wrapper(Stream stream) { + protected Wrapper(final Stream stream) { super(stream); } @Override - public Wrapper wrap(Stream source) { + public Wrapper wrap(final Stream source) { return new Wrapper<>(source); } From f525f211968aaadd8d2899cbe765b8f27743ffe0 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 20 Sep 2022 17:50:43 +0800 Subject: [PATCH 17/73] fix code --- .../main/java/cn/hutool/core/io/FileUtil.java | 2 + .../cn/hutool/core/lang/hash/HashUtil.java | 2 +- .../cn/hutool/core/lang/hash/MurmurHash.java | 240 ++++++++++-------- .../cn/hutool/core/stream/StreamUtil.java | 41 ++- .../core/collection/iter/IterChainTest.java | 22 +- .../java/cn/hutool/core/io/FileUtilTest.java | 4 + ...urMurHashTest.java => MurmurHashTest.java} | 10 +- .../cn/hutool/core/stream/StreamUtilTest.java | 39 +++ 8 files changed, 232 insertions(+), 128 deletions(-) rename hutool-core/src/test/java/cn/hutool/core/lang/hash/{MurMurHashTest.java => MurmurHashTest.java} (85%) diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java index 08ee37de2..231b9319c 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java @@ -3277,6 +3277,8 @@ public class FileUtil extends PathUtil { contentType = "application/x-rar-compressed"; } else if (StrUtil.endWithIgnoreCase(filePath, ".7z")) { contentType = "application/x-7z-compressed"; + } else if (StrUtil.endWithIgnoreCase(filePath, ".wgt")) { + contentType = "application/widget"; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/HashUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/hash/HashUtil.java index e441725ed..2998f52ba 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/HashUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/hash/HashUtil.java @@ -470,7 +470,7 @@ public class HashUtil { * @return hash值 * @since 4.3.3 */ - public static long[] murmur128(final byte[] data) { + public static Number128 murmur128(final byte[] data) { return MurmurHash.hash128(data); } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/MurmurHash.java b/hutool-core/src/main/java/cn/hutool/core/lang/hash/MurmurHash.java index a00d87e5e..dbea48d85 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/MurmurHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/hash/MurmurHash.java @@ -1,8 +1,8 @@ package cn.hutool.core.lang.hash; +import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ByteUtil; import cn.hutool.core.util.CharsetUtil; -import cn.hutool.core.text.StrUtil; import java.io.Serializable; import java.nio.ByteOrder; @@ -10,17 +10,17 @@ import java.nio.charset.Charset; /** * Murmur3 32bit、64bit、128bit 哈希算法实现
- * 此算法来自于:https://github.com/xlturing/Simhash4J/blob/master/src/main/java/bee/simhash/main/Murmur3.java + * 此算法来自于:... * *

* 32-bit Java port of https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp#94
* 128-bit Java port of https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp#255 *

* - * @author looly,Simhash4J + * @author looly, Simhash4J * @since 4.3.3 */ -public class MurmurHash implements Serializable{ +public class MurmurHash implements Serializable { private static final long serialVersionUID = 1L; // Constants for 32 bit variant @@ -68,55 +68,57 @@ public class MurmurHash implements Serializable{ /** * Murmur3 32-bit Hash值计算 * - * @param data 数据 + * @param data 数据 * @param length 长度 - * @param seed 种子,默认0 + * @param seed 种子,默认0 * @return Hash值 */ public static int hash32(final byte[] data, final int length, final int seed) { + return hash32(data, 0, length, seed); + } + + /** + * Murmur3 32-bit Hash值计算 + * + * @param data 数据 + * @param offset 数据开始位置 + * @param length 长度 + * @param seed 种子,默认0 + * @return Hash值 + */ + public static int hash32(final byte[] data, final int offset, final int length, final int seed) { int hash = seed; final int nblocks = length >> 2; // body for (int i = 0; i < nblocks; i++) { - final int i4 = i << 2; - int k = ByteUtil.bytesToInt(data, i4, DEFAULT_ORDER); - + final int i4 = offset + (i << 2); + final int k = ByteUtil.bytesToInt(data, i4, DEFAULT_ORDER); // mix functions - k *= C1_32; - k = Integer.rotateLeft(k, R1_32); - k *= C2_32; - hash ^= k; - hash = Integer.rotateLeft(hash, R2_32) * M_32 + N_32; + hash = mix32(k, hash); } // tail - final int idx = nblocks << 2; + final int idx = offset + (nblocks << 2); int k1 = 0; - switch (length - idx) { - case 3: - k1 ^= data[idx + 2] << 16; - case 2: - k1 ^= data[idx + 1] << 8; - case 1: - k1 ^= data[idx]; + switch (offset + length - idx) { + case 3: + k1 ^= (data[idx + 2] & 0xff) << 16; + case 2: + k1 ^= (data[idx + 1] & 0xff) << 8; + case 1: + k1 ^= (data[idx] & 0xff); - // mix functions - k1 *= C1_32; - k1 = Integer.rotateLeft(k1, R1_32); - k1 *= C2_32; - hash ^= k1; + // mix functions + k1 *= C1_32; + k1 = Integer.rotateLeft(k1, R1_32); + k1 *= C2_32; + hash ^= k1; } // finalization hash ^= length; - hash ^= (hash >>> 16); - hash *= 0x85ebca6b; - hash ^= (hash >>> 13); - hash *= 0xc2b2ae35; - hash ^= (hash >>> 16); - - return hash; + return fmix32(hash); } /** @@ -133,7 +135,6 @@ public class MurmurHash implements Serializable{ * Murmur3 64-bit 算法
* This is essentially MSB 8 bytes of Murmur3 128-bit variant. * - * * @param data 数据 * @return Hash值 */ @@ -142,12 +143,12 @@ public class MurmurHash implements Serializable{ } /** - * Murmur3 64-bit 算法
+ * 类Murmur3 64-bit 算法
* This is essentially MSB 8 bytes of Murmur3 128-bit variant. * - * @param data 数据 + * @param data 数据 * @param length 长度 - * @param seed 种子,默认0 + * @param seed 种子,默认0 * @return Hash值 */ public static long hash64(final byte[] data, final int length, final int seed) { @@ -171,24 +172,24 @@ public class MurmurHash implements Serializable{ long k1 = 0; final int tailStart = nblocks << 3; switch (length - tailStart) { - case 7: - k1 ^= ((long) data[tailStart + 6] & 0xff) << 48; - case 6: - k1 ^= ((long) data[tailStart + 5] & 0xff) << 40; - case 5: - k1 ^= ((long) data[tailStart + 4] & 0xff) << 32; - case 4: - k1 ^= ((long) data[tailStart + 3] & 0xff) << 24; - case 3: - k1 ^= ((long) data[tailStart + 2] & 0xff) << 16; - case 2: - k1 ^= ((long) data[tailStart + 1] & 0xff) << 8; - case 1: - k1 ^= ((long) data[tailStart] & 0xff); - k1 *= C1; - k1 = Long.rotateLeft(k1, R1); - k1 *= C2; - hash ^= k1; + case 7: + k1 ^= ((long) data[tailStart + 6] & 0xff) << 48; + case 6: + k1 ^= ((long) data[tailStart + 5] & 0xff) << 40; + case 5: + k1 ^= ((long) data[tailStart + 4] & 0xff) << 32; + case 4: + k1 ^= ((long) data[tailStart + 3] & 0xff) << 24; + case 3: + k1 ^= ((long) data[tailStart + 2] & 0xff) << 16; + case 2: + k1 ^= ((long) data[tailStart + 1] & 0xff) << 8; + case 1: + k1 ^= ((long) data[tailStart] & 0xff); + k1 *= C1; + k1 = Long.rotateLeft(k1, R1); + k1 *= C2; + hash ^= k1; } // finalization @@ -204,7 +205,7 @@ public class MurmurHash implements Serializable{ * @param data 数据 * @return Hash值 (2 longs) */ - public static long[] hash128(final CharSequence data) { + public static Number128 hash128(final CharSequence data) { return hash128(StrUtil.bytes(data, DEFAULT_CHARSET)); } @@ -214,26 +215,42 @@ public class MurmurHash implements Serializable{ * @param data -数据 * @return Hash值 (2 longs) */ - public static long[] hash128(final byte[] data) { + public static Number128 hash128(final byte[] data) { return hash128(data, data.length, DEFAULT_SEED); } /** * Murmur3 128-bit variant. * - * @param data 数据 + * @param data 数据 * @param length 长度 - * @param seed 种子,默认0 + * @param seed 种子,默认0 * @return Hash值(2 longs) */ - public static long[] hash128(final byte[] data, final int length, final int seed) { + public static Number128 hash128(final byte[] data, final int length, final int seed) { + return hash128(data, 0, length, seed); + } + + /** + * Murmur3 128-bit variant. + * + * @param data 数据 + * @param offset 数据开始位置 + * @param length 长度 + * @param seed 种子,默认0 + * @return Hash值(2 longs) + */ + public static Number128 hash128(final byte[] data, final int offset, final int length, int seed) { + // 避免负数的种子 + seed &= 0xffffffffL; + long h1 = seed; long h2 = seed; final int nblocks = length >> 4; // body for (int i = 0; i < nblocks; i++) { - final int i16 = i << 4; + final int i16 = offset + (i << 4); long k1 = ByteUtil.bytesToLong(data, i16, DEFAULT_ORDER); long k2 = ByteUtil.bytesToLong(data, i16 + 8, DEFAULT_ORDER); @@ -259,47 +276,47 @@ public class MurmurHash implements Serializable{ // tail long k1 = 0; long k2 = 0; - final int tailStart = nblocks << 4; - switch (length - tailStart) { - case 15: - k2 ^= (long) (data[tailStart + 14] & 0xff) << 48; - case 14: - k2 ^= (long) (data[tailStart + 13] & 0xff) << 40; - case 13: - k2 ^= (long) (data[tailStart + 12] & 0xff) << 32; - case 12: - k2 ^= (long) (data[tailStart + 11] & 0xff) << 24; - case 11: - k2 ^= (long) (data[tailStart + 10] & 0xff) << 16; - case 10: - k2 ^= (long) (data[tailStart + 9] & 0xff) << 8; - case 9: - k2 ^= data[tailStart + 8] & 0xff; - k2 *= C2; - k2 = Long.rotateLeft(k2, R3); - k2 *= C1; - h2 ^= k2; + final int tailStart = offset + (nblocks << 4); + switch (offset + length - tailStart) { + case 15: + k2 ^= (long) (data[tailStart + 14] & 0xff) << 48; + case 14: + k2 ^= (long) (data[tailStart + 13] & 0xff) << 40; + case 13: + k2 ^= (long) (data[tailStart + 12] & 0xff) << 32; + case 12: + k2 ^= (long) (data[tailStart + 11] & 0xff) << 24; + case 11: + k2 ^= (long) (data[tailStart + 10] & 0xff) << 16; + case 10: + k2 ^= (long) (data[tailStart + 9] & 0xff) << 8; + case 9: + k2 ^= data[tailStart + 8] & 0xff; + k2 *= C2; + k2 = Long.rotateLeft(k2, R3); + k2 *= C1; + h2 ^= k2; - case 8: - k1 ^= (long) (data[tailStart + 7] & 0xff) << 56; - case 7: - k1 ^= (long) (data[tailStart + 6] & 0xff) << 48; - case 6: - k1 ^= (long) (data[tailStart + 5] & 0xff) << 40; - case 5: - k1 ^= (long) (data[tailStart + 4] & 0xff) << 32; - case 4: - k1 ^= (long) (data[tailStart + 3] & 0xff) << 24; - case 3: - k1 ^= (long) (data[tailStart + 2] & 0xff) << 16; - case 2: - k1 ^= (long) (data[tailStart + 1] & 0xff) << 8; - case 1: - k1 ^= data[tailStart] & 0xff; - k1 *= C1; - k1 = Long.rotateLeft(k1, R1); - k1 *= C2; - h1 ^= k1; + case 8: + k1 ^= (long) (data[tailStart + 7] & 0xff) << 56; + case 7: + k1 ^= (long) (data[tailStart + 6] & 0xff) << 48; + case 6: + k1 ^= (long) (data[tailStart + 5] & 0xff) << 40; + case 5: + k1 ^= (long) (data[tailStart + 4] & 0xff) << 32; + case 4: + k1 ^= (long) (data[tailStart + 3] & 0xff) << 24; + case 3: + k1 ^= (long) (data[tailStart + 2] & 0xff) << 16; + case 2: + k1 ^= (long) (data[tailStart + 1] & 0xff) << 8; + case 1: + k1 ^= data[tailStart] & 0xff; + k1 *= C1; + k1 = Long.rotateLeft(k1, R1); + k1 *= C2; + h1 ^= k1; } // finalization @@ -315,7 +332,24 @@ public class MurmurHash implements Serializable{ h1 += h2; h2 += h1; - return new long[] { h1, h2 }; + return new Number128(h1, h2); + } + + private static int mix32(int k, int hash) { + k *= C1_32; + k = Integer.rotateLeft(k, R1_32); + k *= C2_32; + hash ^= k; + return Integer.rotateLeft(hash, R2_32) * M_32 + N_32; + } + + private static int fmix32(int hash) { + hash ^= (hash >>> 16); + hash *= 0x85ebca6b; + hash ^= (hash >>> 13); + hash *= 0xc2b2ae35; + hash ^= (hash >>> 16); + return hash; } private static long fmix64(long h) { diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java index 3cb1bd849..882599b71 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java @@ -1,6 +1,5 @@ package cn.hutool.core.stream; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.lang.Assert; import cn.hutool.core.stream.spliterators.DropWhileSpliterator; @@ -13,6 +12,8 @@ import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collection; +import java.util.Iterator; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Function; @@ -58,9 +59,33 @@ public class StreamUtil { */ public static Stream of(final Iterable iterable, final boolean parallel) { Assert.notNull(iterable, "Iterable must be not null!"); - return StreamSupport.stream( - Spliterators.spliterator(CollUtil.toCollection(iterable), 0), - parallel); + return iterable instanceof Collection ? + parallel ? ((Collection) iterable).parallelStream() : ((Collection) iterable).stream() : + StreamSupport.stream(iterable.spliterator(), parallel); + } + + /** + * {@link Iterator} 转换为 {@link Stream} + * @param iterator 迭代器 + * @param 集合元素类型 + * @return {@link Stream} + * @throws IllegalArgumentException 如果iterator为null,抛出该异常 + */ + public static Stream ofIter(final Iterator iterator) { + return ofIter(iterator, false); + } + + /** + * {@link Iterator} 转换为 {@link Stream} + * @param iterator 迭代器 + * @param parallel 是否并行 + * @param 集合元素类型 + * @return {@link Stream} + * @throws IllegalArgumentException 如果iterator为null,抛出该异常 + */ + public static Stream ofIter(final Iterator iterator, final boolean parallel) { + Assert.notNull(iterator, "iterator must not be null!"); + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), parallel); } /** @@ -160,7 +185,7 @@ public class StreamUtil { * @param next 用上一个元素作为参数执行并返回一个新的元素 * @return 无限有序流 */ - public static Stream iterate(T seed, Predicate hasNext, UnaryOperator next) { + public static Stream iterate(final T seed, final Predicate hasNext, final UnaryOperator next) { requireNonNull(next); requireNonNull(hasNext); return StreamSupport.stream(IterateSpliterator.create(seed, hasNext, next), false); @@ -177,7 +202,7 @@ public class StreamUtil { * @param predicate 断言 * @return 与指定断言匹配的元素组成的流 */ - public static Stream takeWhile(Stream source, Predicate predicate) { + public static Stream takeWhile(final Stream source, final Predicate predicate) { requireNonNull(source); requireNonNull(predicate); return createStatefulNewStream(source, TakeWhileSpliterator.create(source.spliterator(), predicate)); @@ -194,7 +219,7 @@ public class StreamUtil { * @param predicate 断言 * @return 剩余元素组成的流 */ - public static Stream dropWhile(Stream source, Predicate predicate) { + public static Stream dropWhile(final Stream source, final Predicate predicate) { requireNonNull(source); requireNonNull(predicate); return createStatefulNewStream(source, DropWhileSpliterator.create(source.spliterator(), predicate)); @@ -214,7 +239,7 @@ public class StreamUtil { * @param 新流的元素类型 * @return 新流 */ - private static Stream createStatefulNewStream(Stream source, Spliterator newSpliterator) { + private static Stream createStatefulNewStream(final Stream source, final Spliterator newSpliterator) { // 创建新流 Stream newStream = StreamSupport.stream(newSpliterator, source.isParallel()); // 如果旧流是并行流, 新流主动调用一个有状态的操作, 虽然没有意义, 但是可以让后续的无状态节点正常并发 diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterChainTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterChainTest.java index 26676f85b..5565437e4 100644 --- a/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterChainTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterChainTest.java @@ -14,8 +14,8 @@ public class IterChainTest { @Test public void testAddChain() { - Iterator iter1 = Arrays.asList(1, 2).iterator(); - Iterator iter2 = Arrays.asList(3, 4).iterator(); + final Iterator iter1 = Arrays.asList(1, 2).iterator(); + final Iterator iter2 = Arrays.asList(3, 4).iterator(); IterChain iterChain = new IterChain<>(); Assert.assertSame(iterChain, iterChain.addChain(iter1)); Assert.assertSame(iterChain, iterChain.addChain(iter2)); @@ -27,7 +27,7 @@ public class IterChainTest { @Test public void testHasNext() { - IterChain iterChain = new IterChain<>(); + final IterChain iterChain = new IterChain<>(); Assert.assertFalse(iterChain.hasNext()); Assert.assertFalse(iterChain.addChain(Collections.emptyIterator()).hasNext()); Assert.assertTrue(iterChain.addChain(Arrays.asList(3, 4).iterator()).hasNext()); @@ -35,9 +35,9 @@ public class IterChainTest { @Test public void testNext() { - Iterator iter1 = Arrays.asList(1, 2).iterator(); - Iterator iter2 = Arrays.asList(3, 4).iterator(); - IterChain iterChain = new IterChain<>(); + final Iterator iter1 = Arrays.asList(1, 2).iterator(); + final Iterator iter2 = Arrays.asList(3, 4).iterator(); + final IterChain iterChain = new IterChain<>(); Assert.assertSame(iterChain, iterChain.addChain(iter1)); Assert.assertSame(iterChain, iterChain.addChain(iter2)); Assert.assertEquals((Integer)1, iterChain.next()); @@ -48,20 +48,20 @@ public class IterChainTest { @Test public void testRemove() { - IterChain iterChain = new IterChain<>(); + final IterChain iterChain = new IterChain<>(); iterChain.addChain(Arrays.asList(1, 2).iterator()); Assert.assertThrows(IllegalStateException.class, iterChain::remove); } @Test public void testIterator() { - Iterator iter1 = Arrays.asList(1, 2).iterator(); - Iterator iter2 = Arrays.asList(3, 4).iterator(); - IterChain iterChain = new IterChain<>(); + final Iterator iter1 = Arrays.asList(1, 2).iterator(); + final Iterator iter2 = Arrays.asList(3, 4).iterator(); + final IterChain iterChain = new IterChain<>(); Assert.assertSame(iterChain, iterChain.addChain(iter1)); Assert.assertSame(iterChain, iterChain.addChain(iter2)); - Iterator> iterators = iterChain.iterator(); + final Iterator> iterators = iterChain.iterator(); Assert.assertSame(iter1, iterators.next()); Assert.assertSame(iter2, iterators.next()); } diff --git a/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java index 01b28ba54..dec7bc063 100644 --- a/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java @@ -446,6 +446,10 @@ public class FileUtilTest { Assert.assertEquals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", mimeType); mimeType = FileUtil.getMimeType("test.pptx"); Assert.assertEquals("application/vnd.openxmlformats-officedocument.presentationml.presentation", mimeType); + + // pr#2617@Github + mimeType = FileUtil.getMimeType("test.wgt"); + Assert.assertEquals("application/widget", mimeType); } @Test diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/hash/MurMurHashTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/hash/MurmurHashTest.java similarity index 85% rename from hutool-core/src/test/java/cn/hutool/core/lang/hash/MurMurHashTest.java rename to hutool-core/src/test/java/cn/hutool/core/lang/hash/MurmurHashTest.java index 070a95e92..ec22d015d 100755 --- a/hutool-core/src/test/java/cn/hutool/core/lang/hash/MurMurHashTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/hash/MurmurHashTest.java @@ -4,20 +4,20 @@ import cn.hutool.core.text.StrUtil; import org.junit.Assert; import org.junit.Test; -public class MurMurHashTest { +public class MurmurHashTest { @Test public void hash32Test() { int hv = MurmurHash.hash32(StrUtil.utf8Bytes("你")); - Assert.assertEquals(222142701, hv); + Assert.assertEquals(-1898877446, hv); hv = MurmurHash.hash32(StrUtil.utf8Bytes("你好")); - Assert.assertEquals(1188098267, hv); + Assert.assertEquals(337357348, hv); hv = MurmurHash.hash32(StrUtil.utf8Bytes("见到你很高兴")); - Assert.assertEquals(-1898490321, hv); + Assert.assertEquals(1101306141, hv); hv = MurmurHash.hash32(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); - Assert.assertEquals(-1713131054, hv); + Assert.assertEquals(-785444229, hv); } @Test diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/StreamUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/StreamUtilTest.java index a38d8ff26..153081c59 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/StreamUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/StreamUtilTest.java @@ -1,8 +1,15 @@ package cn.hutool.core.stream; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.collection.SetUtil; import org.junit.Assert; import org.junit.Test; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamUtilTest { @@ -13,4 +20,36 @@ public class StreamUtilTest { final String result = stream.collect(CollectorUtil.joining(",")); Assert.assertEquals("2,4,8,16", result); } + + // === iterator === + @Test + public void streamTestNullIterator() { + Assert.assertThrows(IllegalArgumentException.class, () -> StreamUtil.ofIter((Iterator) null)); + } + + @SuppressWarnings({"RedundantOperationOnEmptyContainer", "RedundantCollectionOperation"}) + @Test + public void streamTestEmptyListToIterator() { + assertStreamIsEmpty(StreamUtil.ofIter(new ArrayList<>().iterator())); + } + + @Test + public void streamTestEmptyIterator() { + assertStreamIsEmpty(StreamUtil.ofIter(Collections.emptyIterator())); + } + + @Test + public void streamTestOrdinaryIterator() { + final ArrayList arrayList = ListUtil.of(1, 2, 3); + Assert.assertArrayEquals(new Integer[]{1, 2, 3}, StreamUtil.ofIter(arrayList.iterator()).toArray()); + + final HashSet hashSet = SetUtil.of(1, 2, 3); + Assert.assertEquals(hashSet, StreamUtil.ofIter(hashSet.iterator()).collect(Collectors.toSet())); + } + + void assertStreamIsEmpty(final Stream stream) { + Assert.assertNotNull(stream); + Assert.assertEquals(0, stream.toArray().length); + } + // ================ stream test end ================ } From 24503fd23dd3518970987fff8d3462ec36e42558 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 20 Sep 2022 18:48:05 +0800 Subject: [PATCH 18/73] fix code --- .../core/{lang/hash => codec}/Number128.java | 2 +- .../core/{lang => codec}/hash/CityHash.java | 49 ++++++++------ .../{lang => codec}/hash/ConsistentHash.java | 2 +- .../core/{lang => codec}/hash/Hash128.java | 9 ++- .../core/{lang => codec}/hash/Hash32.java | 8 ++- .../core/{lang => codec}/hash/Hash64.java | 8 ++- .../core/{lang => codec}/hash/HashUtil.java | 30 +++++---- .../core/{lang => codec}/hash/KetamaHash.java | 15 ++--- .../core/{lang => codec}/hash/MetroHash.java | 66 ++++++++++++------- .../core/{lang => codec}/hash/MurmurHash.java | 38 ++++++----- .../core/{text => codec/hash}/Simhash.java | 28 ++++---- .../{lang => codec}/hash/package-info.java | 2 +- .../cn/hutool/core/collection/CollUtil.java | 2 +- .../java/cn/hutool/core/lang/hash/Hash.java | 19 ------ .../{lang => codec}/hash/CityHashTest.java | 20 +++--- .../{lang => codec}/hash/MetroHashTest.java | 16 ++--- .../core/codec/hash/MurmurHashTest.java | 36 ++++++++++ .../{lang => codec/hash}/SimhashTest.java | 8 +-- .../hutool/core/lang/hash/MurmurHashTest.java | 36 ---------- .../text/bloom/BitMapBloomFilterTest.java | 2 +- .../cn/hutool/core/util/HashUtilTest.java | 2 +- 21 files changed, 215 insertions(+), 183 deletions(-) rename hutool-core/src/main/java/cn/hutool/core/{lang/hash => codec}/Number128.java (97%) rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/CityHash.java (91%) rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/ConsistentHash.java (98%) rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/Hash128.java (56%) mode change 100644 => 100755 rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/Hash32.java (60%) mode change 100644 => 100755 rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/Hash64.java (60%) mode change 100644 => 100755 rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/HashUtil.java (94%) rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/KetamaHash.java (70%) rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/MetroHash.java (84%) rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/MurmurHash.java (88%) rename hutool-core/src/main/java/cn/hutool/core/{text => codec/hash}/Simhash.java (89%) rename hutool-core/src/main/java/cn/hutool/core/{lang => codec}/hash/package-info.java (63%) delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash.java rename hutool-core/src/test/java/cn/hutool/core/{lang => codec}/hash/CityHashTest.java (57%) rename hutool-core/src/test/java/cn/hutool/core/{lang => codec}/hash/MetroHashTest.java (84%) create mode 100755 hutool-core/src/test/java/cn/hutool/core/codec/hash/MurmurHashTest.java rename hutool-core/src/test/java/cn/hutool/core/{lang => codec/hash}/SimhashTest.java (78%) delete mode 100755 hutool-core/src/test/java/cn/hutool/core/lang/hash/MurmurHashTest.java diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Number128.java b/hutool-core/src/main/java/cn/hutool/core/codec/Number128.java similarity index 97% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/Number128.java rename to hutool-core/src/main/java/cn/hutool/core/codec/Number128.java index c3517bc55..e4c0aaa92 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Number128.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Number128.java @@ -1,4 +1,4 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec; /** * 128位数字表示,分高位和低位 diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/CityHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/CityHash.java similarity index 91% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/CityHash.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/CityHash.java index 2274f80ab..bd34700c4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/CityHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/CityHash.java @@ -1,5 +1,6 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; +import cn.hutool.core.codec.Number128; import cn.hutool.core.util.ByteUtil; import java.util.Arrays; @@ -15,18 +16,22 @@ import java.util.Arrays; * @author hexiufeng * @since 5.2.5 */ -public class CityHash { +public class CityHash implements Hash32, Hash64, Hash128{ + public static CityHash INSTANCE = new CityHash(); // Some primes between 2^63 and 2^64 for various uses. private static final long k0 = 0xc3a5c85c97cb3127L; private static final long k1 = 0xb492b66fbe98f273L; private static final long k2 = 0x9ae16a3b2f90404fL; - private static final long kMul = 0x9ddfea08eb382d69L; // Magic numbers for 32-bit hashing. Copied from Murmur3. private static final int c1 = 0xcc9e2d51; private static final int c2 = 0x1b873593; + @Override + public Number encode(final byte[] bytes) { + return hash64(bytes); + } /** * 计算32位City Hash值 @@ -34,7 +39,8 @@ public class CityHash { * @param data 数据 * @return hash值 */ - public static int hash32(final byte[] data) { + @Override + public int hash32(final byte[] data) { final int len = data.length; if (len <= 24) { return len <= 12 ? @@ -117,7 +123,8 @@ public class CityHash { * @param data 数据 * @return hash值 */ - public static long hash64(final byte[] data) { + @Override + public long hash64(final byte[] data) { int len = data.length; if (len <= 32) { if (len <= 16) { @@ -168,7 +175,7 @@ public class CityHash { * @param seed1 种子2 * @return hash值 */ - public static long hash64(final byte[] data, final long seed0, final long seed1) { + public long hash64(final byte[] data, final long seed0, final long seed1) { return hashLen16(hash64(data) - seed0, seed1); } @@ -179,7 +186,7 @@ public class CityHash { * @param seed 种子2 * @return hash值 */ - public static long hash64(final byte[] data, final long seed) { + public long hash64(final byte[] data, final long seed) { return hash64(data, k2, seed); } @@ -189,7 +196,8 @@ public class CityHash { * @param data 数据 * @return hash值 */ - public static Number128 hash128(final byte[] data) { + @Override + public Number128 hash128(final byte[] data) { final int len = data.length; return len >= 16 ? hash128(data, 16, @@ -204,12 +212,12 @@ public class CityHash { * @param seed 种子 * @return hash值 */ - public static Number128 hash128(final byte[] data, final Number128 seed) { + public Number128 hash128(final byte[] data, final Number128 seed) { return hash128(data, 0, seed); } //------------------------------------------------------------------------------------------------------- Private method start - private static Number128 hash128(final byte[] byteArray, final int start, final Number128 seed) { + private Number128 hash128(final byte[] byteArray, final int start, final Number128 seed) { int len = byteArray.length - start; if (len < 128) { @@ -283,7 +291,7 @@ public class CityHash { } - private static int hash32Len0to4(final byte[] byteArray) { + private int hash32Len0to4(final byte[] byteArray) { int b = 0; int c = 9; final int len = byteArray.length; @@ -294,7 +302,7 @@ public class CityHash { return fmix(mur(b, mur(len, c))); } - private static int hash32Len5to12(final byte[] byteArray) { + private int hash32Len5to12(final byte[] byteArray) { final int len = byteArray.length; int a = len; int b = len * 5; @@ -306,7 +314,7 @@ public class CityHash { return fmix(mur(c, mur(b, mur(a, d)))); } - private static int hash32Len13to24(final byte[] byteArray) { + private int hash32Len13to24(final byte[] byteArray) { final int len = byteArray.length; final int a = fetch32(byteArray, (len >>> 1) - 4); final int b = fetch32(byteArray, 4); @@ -319,7 +327,7 @@ public class CityHash { return fmix(mur(f, mur(e, mur(d, mur(c, mur(b, mur(a, h))))))); } - private static long hashLen0to16(final byte[] byteArray) { + private long hashLen0to16(final byte[] byteArray) { final int len = byteArray.length; if (len >= 8) { final long mul = k2 + len * 2L; @@ -346,7 +354,7 @@ public class CityHash { } // This probably works well for 16-byte strings as well, but it may be overkill in that case. - private static long hashLen17to32(final byte[] byteArray) { + private long hashLen17to32(final byte[] byteArray) { final int len = byteArray.length; final long mul = k2 + len * 2L; final long a = fetch64(byteArray, 0) * k1; @@ -357,7 +365,7 @@ public class CityHash { a + rotate64(b + k2, 18) + c, mul); } - private static long hashLen33to64(final byte[] byteArray) { + private long hashLen33to64(final byte[] byteArray) { final int len = byteArray.length; final long mul = k2 + len * 2L; long a = fetch64(byteArray, 0) * k2; @@ -407,12 +415,13 @@ public class CityHash { return b; } - private static long hashLen16(final long u, final long v) { + private long hashLen16(final long u, final long v) { return hash128to64(new Number128(u, v)); } - private static long hash128to64(final Number128 number128) { + private long hash128to64(final Number128 number128) { // Murmur-inspired hashing. + final long kMul = 0x9ddfea08eb382d69L; long a = (number128.getLowValue() ^ number128.getHighValue()) * kMul; a ^= (a >>> 47); long b = (number128.getHighValue() ^ a) * kMul; @@ -434,7 +443,7 @@ public class CityHash { return h; } - private static int mur(int a, int h) { + private int mur(int a, int h) { // Helper from Murmur3 for combining two 32-bit values. a *= c1; a = rotate32(a, 17); @@ -466,7 +475,7 @@ public class CityHash { b); } - private static Number128 cityMurmur(final byte[] byteArray, final Number128 seed) { + private Number128 cityMurmur(final byte[] byteArray, final Number128 seed) { final int len = byteArray.length; long a = seed.getLowValue(); long b = seed.getHighValue(); diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/ConsistentHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/ConsistentHash.java similarity index 98% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/ConsistentHash.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/ConsistentHash.java index b98915953..79cca4134 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/ConsistentHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/ConsistentHash.java @@ -1,4 +1,4 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; import java.io.Serializable; import java.util.Collection; diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash128.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash128.java old mode 100644 new mode 100755 similarity index 56% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash128.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash128.java index e492e888e..07ed7823b --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash128.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash128.java @@ -1,4 +1,7 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; + +import cn.hutool.core.codec.Encoder; +import cn.hutool.core.codec.Number128; /** * Hash计算接口 @@ -8,7 +11,7 @@ package cn.hutool.core.lang.hash; * @since 5.2.5 */ @FunctionalInterface -public interface Hash128 extends Hash{ +public interface Hash128 extends Encoder { /** * 计算Hash值 @@ -19,7 +22,7 @@ public interface Hash128 extends Hash{ Number128 hash128(T t); @Override - default Number hash(final T t){ + default Number encode(final T t){ return hash128(t); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash32.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash32.java old mode 100644 new mode 100755 similarity index 60% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash32.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash32.java index ea53b02b5..668fba6ac --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash32.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash32.java @@ -1,4 +1,6 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; + +import cn.hutool.core.codec.Encoder; /** * Hash计算接口 @@ -8,7 +10,7 @@ package cn.hutool.core.lang.hash; * @since 5.2.5 */ @FunctionalInterface -public interface Hash32 extends Hash{ +public interface Hash32 extends Encoder { /** * 计算Hash值 * @@ -18,7 +20,7 @@ public interface Hash32 extends Hash{ int hash32(T t); @Override - default Number hash(final T t){ + default Number encode(final T t){ return hash32(t); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash64.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash64.java old mode 100644 new mode 100755 similarity index 60% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash64.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash64.java index 204669685..8ad94e047 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash64.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/Hash64.java @@ -1,4 +1,6 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; + +import cn.hutool.core.codec.Encoder; /** * Hash计算接口 @@ -8,7 +10,7 @@ package cn.hutool.core.lang.hash; * @since 5.2.5 */ @FunctionalInterface -public interface Hash64 extends Hash{ +public interface Hash64 extends Encoder { /** * 计算Hash值 * @@ -18,7 +20,7 @@ public interface Hash64 extends Hash{ long hash64(T t); @Override - default Number hash(final T t){ + default Number encode(final T t){ return hash64(t); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/HashUtil.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/HashUtil.java similarity index 94% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/HashUtil.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/HashUtil.java index 2998f52ba..a54873d8d 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/HashUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/HashUtil.java @@ -1,4 +1,6 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; + +import cn.hutool.core.codec.Number128; /** * Hash算法大全
@@ -449,7 +451,7 @@ public class HashUtil { * @since 4.3.3 */ public static int murmur32(final byte[] data) { - return MurmurHash.hash32(data); + return MurmurHash.INSTANCE.hash32(data); } /** @@ -460,7 +462,7 @@ public class HashUtil { * @since 4.3.3 */ public static long murmur64(final byte[] data) { - return MurmurHash.hash64(data); + return MurmurHash.INSTANCE.hash64(data); } /** @@ -471,7 +473,7 @@ public class HashUtil { * @since 4.3.3 */ public static Number128 murmur128(final byte[] data) { - return MurmurHash.hash128(data); + return MurmurHash.INSTANCE.hash128(data); } /** @@ -482,7 +484,7 @@ public class HashUtil { * @since 5.2.5 */ public static int cityHash32(final byte[] data) { - return CityHash.hash32(data); + return CityHash.INSTANCE.hash32(data); } /** @@ -494,7 +496,7 @@ public class HashUtil { * @since 5.2.5 */ public static long cityHash64(final byte[] data, final long seed) { - return CityHash.hash64(data, seed); + return CityHash.INSTANCE.hash64(data, seed); } /** @@ -507,7 +509,7 @@ public class HashUtil { * @since 5.2.5 */ public static long cityHash64(final byte[] data, final long seed0, final long seed1) { - return CityHash.hash64(data, seed0, seed1); + return CityHash.INSTANCE.hash64(data, seed0, seed1); } /** @@ -518,7 +520,7 @@ public class HashUtil { * @since 5.2.5 */ public static long cityHash64(final byte[] data) { - return CityHash.hash64(data); + return CityHash.INSTANCE.hash64(data); } /** @@ -529,7 +531,7 @@ public class HashUtil { * @since 5.2.5 */ public static long[] cityHash128(final byte[] data) { - return CityHash.hash128(data).getLongArray(); + return CityHash.INSTANCE.hash128(data).getLongArray(); } /** @@ -541,7 +543,7 @@ public class HashUtil { * @since 5.2.5 */ public static long[] cityHash128(final byte[] data, final Number128 seed) { - return CityHash.hash128(data, seed).getLongArray(); + return CityHash.INSTANCE.hash128(data, seed).getLongArray(); } /** @@ -552,7 +554,7 @@ public class HashUtil { * @return hash值 */ public static long metroHash64(final byte[] data, final long seed) { - return MetroHash.hash64(data, seed); + return MetroHash.INSTANCE.hash64(data, seed); } /** @@ -562,7 +564,7 @@ public class HashUtil { * @return hash值 */ public static long metroHash64(final byte[] data) { - return MetroHash.hash64(data); + return MetroHash.INSTANCE.hash64(data); } /** @@ -573,7 +575,7 @@ public class HashUtil { * @return hash值,long[0]:低位,long[1]:高位 */ public static long[] metroHash128(final byte[] data, final long seed) { - return MetroHash.hash128(data, seed).getLongArray(); + return MetroHash.INSTANCE.hash128(data, seed).getLongArray(); } /** @@ -583,7 +585,7 @@ public class HashUtil { * @return hash值,long[0]:低位,long[1]:高位 */ public static long[] metroHash128(final byte[] data) { - return MetroHash.hash128(data).getLongArray(); + return MetroHash.INSTANCE.hash128(data).getLongArray(); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/KetamaHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/KetamaHash.java similarity index 70% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/KetamaHash.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/KetamaHash.java index 397dfb7e5..0b5c5585d 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/KetamaHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/KetamaHash.java @@ -1,7 +1,6 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; import cn.hutool.core.exceptions.UtilException; -import cn.hutool.core.text.StrUtil; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -12,10 +11,10 @@ import java.security.NoSuchAlgorithmException; * @author looly * @since 5.7.20 */ -public class KetamaHash implements Hash64, Hash32 { +public class KetamaHash implements Hash64, Hash32 { @Override - public long hash64(final String key) { + public long hash64(final byte[] key) { final byte[] bKey = md5(key); return ((long) (bKey[3] & 0xFF) << 24) | ((long) (bKey[2] & 0xFF) << 16) @@ -24,12 +23,12 @@ public class KetamaHash implements Hash64, Hash32 { } @Override - public int hash32(final String key) { + public int hash32(final byte[] key) { return (int) (hash64(key) & 0xffffffffL); } @Override - public Number hash(final String key) { + public Number encode(final byte[] key) { return hash64(key); } @@ -39,13 +38,13 @@ public class KetamaHash implements Hash64, Hash32 { * @param key 被计算的键 * @return MD5值 */ - private static byte[] md5(final String key) { + private static byte[] md5(final byte[] key) { final MessageDigest md5; try { md5 = MessageDigest.getInstance("MD5"); } catch (final NoSuchAlgorithmException e) { throw new UtilException("MD5 algorithm not suooport!", e); } - return md5.digest(StrUtil.utf8Bytes(key)); + return md5.digest(key); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/MetroHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/MetroHash.java similarity index 84% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/MetroHash.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/MetroHash.java index 0f96a5e80..56a9388c7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/MetroHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/MetroHash.java @@ -1,5 +1,6 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; +import cn.hutool.core.codec.Number128; import cn.hutool.core.util.ByteUtil; import java.nio.ByteOrder; @@ -13,35 +14,35 @@ import java.util.Arrays; * 官方实现: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 { +public class MetroHash implements Hash64, Hash128 { + public static MetroHash INSTANCE = new 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; + @Override + public Number encode(final byte[] bytes) { + return hash64(bytes); + } - /** - * 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(final byte[] data) { + @Override + public long hash64(final byte[] data) { return hash64(data, 1337); } - public static Number128 hash128(final byte[] data) { - return hash128(data, 1337); - } + /** + * 计算64位Hash值 + * + * @param data 数据 + * @param seed 种子 + * @return hash64 + */ + public long hash64(final byte[] data, final long seed) { + final long k0_64 = 0xD6D018F5; + final long k1_64 = 0xA2AA033B; + final long k2_64 = 0x62992FC1; + final long k3_64 = 0x30BC5B29; - public static long hash64(final byte[] data, final long seed) { byte[] buffer = data; long hash = (seed + k2_64) * k0_64; @@ -113,7 +114,24 @@ public class MetroHash { return hash; } - public static Number128 hash128(final byte[] data, final long seed) { + @Override + public Number128 hash128(final byte[] data) { + return hash128(data, 1337); + } + + /** + * 计算128位hash值 + * + * @param data 数据 + * @param seed 种子 + * @return hash128 + */ + public Number128 hash128(final byte[] data, final long seed) { + final long k0_128 = 0xC83A91E1; + final long k1_128 = 0x8648DBDB; + final long k2_128 = 0x7BDEC03B; + final long k3_128 = 0x2F5870A5; + byte[] buffer = data; long v0, v1, v2, v3; @@ -193,6 +211,7 @@ public class MetroHash { } + // region =========== Private methods private static long littleEndian64(final byte[] b, final int start) { return ByteUtil.bytesToLong(b, start, ByteOrder.LITTLE_ENDIAN); } @@ -214,4 +233,5 @@ public class MetroHash { private static long rotateRight(final long val, final int shift) { return (val >> shift) | (val << (64 - shift)); } + // endregion =========== Private methods } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/MurmurHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/MurmurHash.java similarity index 88% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/MurmurHash.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/MurmurHash.java index dbea48d85..0f3065973 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/MurmurHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/MurmurHash.java @@ -1,10 +1,10 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; +import cn.hutool.core.codec.Number128; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ByteUtil; import cn.hutool.core.util.CharsetUtil; -import java.io.Serializable; import java.nio.ByteOrder; import java.nio.charset.Charset; @@ -20,8 +20,8 @@ import java.nio.charset.Charset; * @author looly, Simhash4J * @since 4.3.3 */ -public class MurmurHash implements Serializable { - private static final long serialVersionUID = 1L; +public class MurmurHash implements Hash32, Hash64, Hash128{ + public static final MurmurHash INSTANCE = new MurmurHash(); // Constants for 32 bit variant private static final int C1_32 = 0xcc9e2d51; @@ -45,13 +45,18 @@ public class MurmurHash implements Serializable { private static final Charset DEFAULT_CHARSET = CharsetUtil.UTF_8; private static final ByteOrder DEFAULT_ORDER = ByteOrder.LITTLE_ENDIAN; + @Override + public Number encode(final byte[] bytes) { + return hash128(bytes); + } + /** * Murmur3 32-bit Hash值计算 * * @param data 数据 * @return Hash值 */ - public static int hash32(final CharSequence data) { + public int hash32(final CharSequence data) { return hash32(StrUtil.bytes(data, DEFAULT_CHARSET)); } @@ -61,7 +66,8 @@ public class MurmurHash implements Serializable { * @param data 数据 * @return Hash值 */ - public static int hash32(final byte[] data) { + @Override + public int hash32(final byte[] data) { return hash32(data, data.length, DEFAULT_SEED); } @@ -73,7 +79,7 @@ public class MurmurHash implements Serializable { * @param seed 种子,默认0 * @return Hash值 */ - public static int hash32(final byte[] data, final int length, final int seed) { + public int hash32(final byte[] data, final int length, final int seed) { return hash32(data, 0, length, seed); } @@ -86,7 +92,7 @@ public class MurmurHash implements Serializable { * @param seed 种子,默认0 * @return Hash值 */ - public static int hash32(final byte[] data, final int offset, final int length, final int seed) { + public int hash32(final byte[] data, final int offset, final int length, final int seed) { int hash = seed; final int nblocks = length >> 2; @@ -127,7 +133,7 @@ public class MurmurHash implements Serializable { * @param data 数据 * @return Hash值 */ - public static long hash64(final CharSequence data) { + public long hash64(final CharSequence data) { return hash64(StrUtil.bytes(data, DEFAULT_CHARSET)); } @@ -138,7 +144,8 @@ public class MurmurHash implements Serializable { * @param data 数据 * @return Hash值 */ - public static long hash64(final byte[] data) { + @Override + public long hash64(final byte[] data) { return hash64(data, data.length, DEFAULT_SEED); } @@ -151,7 +158,7 @@ public class MurmurHash implements Serializable { * @param seed 种子,默认0 * @return Hash值 */ - public static long hash64(final byte[] data, final int length, final int seed) { + public long hash64(final byte[] data, final int length, final int seed) { long hash = seed; final int nblocks = length >> 3; @@ -205,7 +212,7 @@ public class MurmurHash implements Serializable { * @param data 数据 * @return Hash值 (2 longs) */ - public static Number128 hash128(final CharSequence data) { + public Number128 hash128(final CharSequence data) { return hash128(StrUtil.bytes(data, DEFAULT_CHARSET)); } @@ -215,7 +222,8 @@ public class MurmurHash implements Serializable { * @param data -数据 * @return Hash值 (2 longs) */ - public static Number128 hash128(final byte[] data) { + @Override + public Number128 hash128(final byte[] data) { return hash128(data, data.length, DEFAULT_SEED); } @@ -227,7 +235,7 @@ public class MurmurHash implements Serializable { * @param seed 种子,默认0 * @return Hash值(2 longs) */ - public static Number128 hash128(final byte[] data, final int length, final int seed) { + public Number128 hash128(final byte[] data, final int length, final int seed) { return hash128(data, 0, length, seed); } @@ -240,7 +248,7 @@ public class MurmurHash implements Serializable { * @param seed 种子,默认0 * @return Hash值(2 longs) */ - public static Number128 hash128(final byte[] data, final int offset, final int length, int seed) { + public Number128 hash128(final byte[] data, final int offset, final int length, int seed) { // 避免负数的种子 seed &= 0xffffffffL; diff --git a/hutool-core/src/main/java/cn/hutool/core/text/Simhash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/Simhash.java similarity index 89% rename from hutool-core/src/main/java/cn/hutool/core/text/Simhash.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/Simhash.java index a633c599d..fa90e43a2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/Simhash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/Simhash.java @@ -1,6 +1,4 @@ -package cn.hutool.core.text; - -import cn.hutool.core.lang.hash.MurmurHash; +package cn.hutool.core.codec.hash; import java.math.BigInteger; import java.util.ArrayList; @@ -23,16 +21,22 @@ import java.util.concurrent.locks.StampedLock; * @author Looly, litaoxiao * @since 4.3.3 */ -public class Simhash { +public class Simhash implements Hash64> { private final int bitNum = 64; - /** 存储段数,默认按照4段进行simhash存储 */ + /** + * 存储段数,默认按照4段进行simhash存储 + */ private final int fracCount; private final int fracBitNum; - /** 汉明距离的衡量标准,小于此距离标准表示相似 */ + /** + * 汉明距离的衡量标准,小于此距离标准表示相似 + */ private final int hammingThresh; - /** 按照分段存储simhash,查找更快速 */ + /** + * 按照分段存储simhash,查找更快速 + */ private final List>> storage; private final StampedLock lock = new StampedLock(); @@ -46,7 +50,7 @@ public class Simhash { /** * 构造 * - * @param fracCount 存储段数 + * @param fracCount 存储段数 * @param hammingThresh 汉明距离的衡量标准 */ public Simhash(final int fracCount, final int hammingThresh) { @@ -65,13 +69,14 @@ public class Simhash { * @param segList 分词的词列表 * @return Hash值 */ - public long hash(final Collection segList) { + @Override + public long hash64(final Collection segList) { final int bitNum = this.bitNum; // 按照词语的hash值,计算simHashWeight(低位对齐) final int[] weight = new int[bitNum]; long wordHash; for (final CharSequence seg : segList) { - wordHash = MurmurHash.hash64(seg); + wordHash = MurmurHash.INSTANCE.hash64(seg); for (int i = 0; i < bitNum; i++) { if (((wordHash >> i) & 1) == 1) weight[i] += 1; @@ -96,7 +101,7 @@ public class Simhash { * @return 是否重复 */ public boolean equals(final Collection segList) { - final long simhash = hash(segList); + final long simhash = hash64(segList); final List fracList = splitSimhash(simhash); final int hammingThresh = this.hammingThresh; @@ -153,6 +158,7 @@ public class Simhash { } //------------------------------------------------------------------------------------------------------ Private method start + /** * 计算汉明距离 * diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/package-info.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/package-info.java similarity index 63% rename from hutool-core/src/main/java/cn/hutool/core/lang/hash/package-info.java rename to hutool-core/src/main/java/cn/hutool/core/codec/hash/package-info.java index 55e825f3b..0a0123eaa 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/package-info.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/package-info.java @@ -4,4 +4,4 @@ * @author looly * */ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java index b67cda84f..44efd239f 100755 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java @@ -9,7 +9,7 @@ import cn.hutool.core.comparator.PropertyComparator; import cn.hutool.core.convert.CompositeConverter; import cn.hutool.core.convert.Convert; import cn.hutool.core.exceptions.UtilException; -import cn.hutool.core.lang.hash.Hash32; +import cn.hutool.core.codec.hash.Hash32; import cn.hutool.core.map.MapUtil; import cn.hutool.core.reflect.ClassUtil; import cn.hutool.core.reflect.ConstructorUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash.java b/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash.java deleted file mode 100644 index 8ad0a9e35..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/hash/Hash.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.hutool.core.lang.hash; - -/** - * Hash计算接口 - * - * @param 被计算hash的对象类型 - * @author looly - * @since 5.7.15 - */ -@FunctionalInterface -public interface Hash { - /** - * 计算Hash值 - * - * @param t 对象 - * @return hash - */ - Number hash(T t); -} diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/hash/CityHashTest.java b/hutool-core/src/test/java/cn/hutool/core/codec/hash/CityHashTest.java similarity index 57% rename from hutool-core/src/test/java/cn/hutool/core/lang/hash/CityHashTest.java rename to hutool-core/src/test/java/cn/hutool/core/codec/hash/CityHashTest.java index 1fa261e44..d48547415 100755 --- a/hutool-core/src/test/java/cn/hutool/core/lang/hash/CityHashTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/codec/hash/CityHashTest.java @@ -1,4 +1,4 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; import cn.hutool.core.text.StrUtil; import org.junit.Assert; @@ -8,29 +8,31 @@ public class CityHashTest { @Test public void hash32Test() { - int hv = CityHash.hash32(StrUtil.utf8Bytes("你")); + final CityHash cityHash = CityHash.INSTANCE; + int hv = cityHash.hash32(StrUtil.utf8Bytes("你")); Assert.assertEquals(1290029860, hv); - hv = CityHash.hash32(StrUtil.utf8Bytes("你好")); + hv = cityHash.hash32(StrUtil.utf8Bytes("你好")); Assert.assertEquals(1374181357, hv); - hv = CityHash.hash32(StrUtil.utf8Bytes("见到你很高兴")); + hv = cityHash.hash32(StrUtil.utf8Bytes("见到你很高兴")); Assert.assertEquals(1475516842, hv); - hv = CityHash.hash32(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); + hv = cityHash.hash32(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); Assert.assertEquals(0x51020cae, hv); } @Test public void hash64Test() { - long hv = CityHash.hash64(StrUtil.utf8Bytes("你")); + final CityHash cityHash = CityHash.INSTANCE; + long hv = cityHash.hash64(StrUtil.utf8Bytes("你")); Assert.assertEquals(-4296898700418225525L, hv); - hv = CityHash.hash64(StrUtil.utf8Bytes("你好")); + hv = cityHash.hash64(StrUtil.utf8Bytes("你好")); Assert.assertEquals(-4294276205456761303L, hv); - hv = CityHash.hash64(StrUtil.utf8Bytes("见到你很高兴")); + hv = cityHash.hash64(StrUtil.utf8Bytes("见到你很高兴")); Assert.assertEquals(272351505337503793L, hv); - hv = CityHash.hash64(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); + hv = cityHash.hash64(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); Assert.assertEquals(-8234735310919228703L, hv); } } diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/hash/MetroHashTest.java b/hutool-core/src/test/java/cn/hutool/core/codec/hash/MetroHashTest.java similarity index 84% rename from hutool-core/src/test/java/cn/hutool/core/lang/hash/MetroHashTest.java rename to hutool-core/src/test/java/cn/hutool/core/codec/hash/MetroHashTest.java index a8f4c9c69..3222ef0ea 100755 --- a/hutool-core/src/test/java/cn/hutool/core/lang/hash/MetroHashTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/codec/hash/MetroHashTest.java @@ -1,4 +1,4 @@ -package cn.hutool.core.lang.hash; +package cn.hutool.core.codec.hash; import cn.hutool.core.util.CharsetUtil; @@ -16,20 +16,20 @@ public class MetroHashTest { @Test public void testEmpty() { - Assert.assertEquals("31290877cceaea29", HexUtil.toHex(MetroHash.hash64(StrUtil.utf8Bytes(""), 0))); + Assert.assertEquals("31290877cceaea29", HexUtil.toHex(MetroHash.INSTANCE.hash64(StrUtil.utf8Bytes(""), 0))); } @Test public void metroHash64Test() { final byte[] str = "我是一段测试123".getBytes(CharsetUtil.UTF_8); - final long hash64 = MetroHash.hash64(str); + final long hash64 = MetroHash.INSTANCE.hash64(str); Assert.assertEquals(62920234463891865L, hash64); } @Test public void metroHash128Test() { final byte[] str = "我是一段测试123".getBytes(CharsetUtil.UTF_8); - final long[] hash128 = MetroHash.hash128(str).getLongArray(); + final long[] hash128 = MetroHash.INSTANCE.hash128(str).getLongArray(); Assert.assertEquals(4956592424592439349L, hash128[0]); Assert.assertEquals(6301214698325086246L, hash128[1]); } @@ -43,13 +43,13 @@ public class MetroHashTest { final String[] strArray = getRandomStringArray(); final long startCity = System.currentTimeMillis(); for (final String s : strArray) { - CityHash.hash64(s.getBytes()); + CityHash.INSTANCE.hash64(s.getBytes()); } final long endCity = System.currentTimeMillis(); final long startMetro = System.currentTimeMillis(); for (final String s : strArray) { - MetroHash.hash64(StrUtil.utf8Bytes(s)); + MetroHash.INSTANCE.hash64(StrUtil.utf8Bytes(s)); } final long endMetro = System.currentTimeMillis(); @@ -67,13 +67,13 @@ public class MetroHashTest { final String[] strArray = getRandomStringArray(); final long startCity = System.currentTimeMillis(); for (final String s : strArray) { - CityHash.hash128(s.getBytes()); + CityHash.INSTANCE.hash128(s.getBytes()); } final long endCity = System.currentTimeMillis(); final long startMetro = System.currentTimeMillis(); for (final String s : strArray) { - MetroHash.hash128(StrUtil.utf8Bytes(s)); + MetroHash.INSTANCE.hash128(StrUtil.utf8Bytes(s)); } final long endMetro = System.currentTimeMillis(); diff --git a/hutool-core/src/test/java/cn/hutool/core/codec/hash/MurmurHashTest.java b/hutool-core/src/test/java/cn/hutool/core/codec/hash/MurmurHashTest.java new file mode 100755 index 000000000..68c4a25ea --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/codec/hash/MurmurHashTest.java @@ -0,0 +1,36 @@ +package cn.hutool.core.codec.hash; + +import cn.hutool.core.text.StrUtil; +import org.junit.Assert; +import org.junit.Test; + +public class MurmurHashTest { + + @Test + public void hash32Test() { + int hv = MurmurHash.INSTANCE.hash32(StrUtil.utf8Bytes("你")); + Assert.assertEquals(-1898877446, hv); + + hv = MurmurHash.INSTANCE.hash32(StrUtil.utf8Bytes("你好")); + Assert.assertEquals(337357348, hv); + + hv = MurmurHash.INSTANCE.hash32(StrUtil.utf8Bytes("见到你很高兴")); + Assert.assertEquals(1101306141, hv); + hv = MurmurHash.INSTANCE.hash32(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); + Assert.assertEquals(-785444229, hv); + } + + @Test + public void hash64Test() { + long hv = MurmurHash.INSTANCE.hash64(StrUtil.utf8Bytes("你")); + Assert.assertEquals(-1349759534971957051L, hv); + + hv = MurmurHash.INSTANCE.hash64(StrUtil.utf8Bytes("你好")); + Assert.assertEquals(-7563732748897304996L, hv); + + hv = MurmurHash.INSTANCE.hash64(StrUtil.utf8Bytes("见到你很高兴")); + Assert.assertEquals(-766658210119995316L, hv); + hv = MurmurHash.INSTANCE.hash64(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); + Assert.assertEquals(-7469283059271653317L, hv); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/SimhashTest.java b/hutool-core/src/test/java/cn/hutool/core/codec/hash/SimhashTest.java similarity index 78% rename from hutool-core/src/test/java/cn/hutool/core/lang/SimhashTest.java rename to hutool-core/src/test/java/cn/hutool/core/codec/hash/SimhashTest.java index 12dc8fe4b..e1369973b 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/SimhashTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/codec/hash/SimhashTest.java @@ -1,11 +1,9 @@ -package cn.hutool.core.lang; +package cn.hutool.core.codec.hash; +import cn.hutool.core.text.StrUtil; import org.junit.Assert; import org.junit.Test; -import cn.hutool.core.text.Simhash; -import cn.hutool.core.text.StrUtil; - public class SimhashTest { @Test @@ -14,7 +12,7 @@ public class SimhashTest { final String text2 = "我是 一个 普通 字符串"; final Simhash simhash = new Simhash(); - final long hash = simhash.hash(StrUtil.split(text1, ' ')); + final long hash = simhash.hash64(StrUtil.split(text1, ' ')); Assert.assertTrue(hash != 0); simhash.store(hash); diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/hash/MurmurHashTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/hash/MurmurHashTest.java deleted file mode 100755 index ec22d015d..000000000 --- a/hutool-core/src/test/java/cn/hutool/core/lang/hash/MurmurHashTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.hutool.core.lang.hash; - -import cn.hutool.core.text.StrUtil; -import org.junit.Assert; -import org.junit.Test; - -public class MurmurHashTest { - - @Test - public void hash32Test() { - int hv = MurmurHash.hash32(StrUtil.utf8Bytes("你")); - Assert.assertEquals(-1898877446, hv); - - hv = MurmurHash.hash32(StrUtil.utf8Bytes("你好")); - Assert.assertEquals(337357348, hv); - - hv = MurmurHash.hash32(StrUtil.utf8Bytes("见到你很高兴")); - Assert.assertEquals(1101306141, hv); - hv = MurmurHash.hash32(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); - Assert.assertEquals(-785444229, hv); - } - - @Test - public void hash64Test() { - long hv = MurmurHash.hash64(StrUtil.utf8Bytes("你")); - Assert.assertEquals(-1349759534971957051L, hv); - - hv = MurmurHash.hash64(StrUtil.utf8Bytes("你好")); - Assert.assertEquals(-7563732748897304996L, hv); - - hv = MurmurHash.hash64(StrUtil.utf8Bytes("见到你很高兴")); - Assert.assertEquals(-766658210119995316L, hv); - hv = MurmurHash.hash64(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件")); - Assert.assertEquals(-7469283059271653317L, hv); - } -} diff --git a/hutool-core/src/test/java/cn/hutool/core/text/bloom/BitMapBloomFilterTest.java b/hutool-core/src/test/java/cn/hutool/core/text/bloom/BitMapBloomFilterTest.java index 3353a2d86..ee077eca6 100644 --- a/hutool-core/src/test/java/cn/hutool/core/text/bloom/BitMapBloomFilterTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/bloom/BitMapBloomFilterTest.java @@ -1,6 +1,6 @@ package cn.hutool.core.text.bloom; -import cn.hutool.core.lang.hash.HashUtil; +import cn.hutool.core.codec.hash.HashUtil; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-core/src/test/java/cn/hutool/core/util/HashUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/HashUtilTest.java index cc2e12319..66002e92b 100755 --- a/hutool-core/src/test/java/cn/hutool/core/util/HashUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/HashUtilTest.java @@ -1,6 +1,6 @@ package cn.hutool.core.util; -import cn.hutool.core.lang.hash.HashUtil; +import cn.hutool.core.codec.hash.HashUtil; import cn.hutool.core.text.StrUtil; import org.junit.Assert; import org.junit.Test; From 1f0909f11464383e61765050d051304613d1a6de Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 20 Sep 2022 18:53:25 +0800 Subject: [PATCH 19/73] fix code --- .../java/cn/hutool/core/{lang => reflect}/ClassScanner.java | 2 +- .../src/main/java/cn/hutool/core/reflect/ClassUtil.java | 1 - .../cn/hutool/core/{lang => reflect}/ClassScanerTest.java | 4 +++- 3 files changed, 4 insertions(+), 3 deletions(-) rename hutool-core/src/main/java/cn/hutool/core/{lang => reflect}/ClassScanner.java (99%) rename hutool-core/src/test/java/cn/hutool/core/{lang => reflect}/ClassScanerTest.java (88%) diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassScanner.java similarity index 99% rename from hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java rename to hutool-core/src/main/java/cn/hutool/core/reflect/ClassScanner.java index 3efc5c1e2..0538f0412 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassScanner.java @@ -1,4 +1,4 @@ -package cn.hutool.core.lang; +package cn.hutool.core.reflect; import cn.hutool.core.classloader.ClassLoaderUtil; import cn.hutool.core.collection.CollUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java index 7191fc777..a86c2b986 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java @@ -6,7 +6,6 @@ import cn.hutool.core.convert.BasicType; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.lang.ClassScanner; import cn.hutool.core.net.URLDecoder; import cn.hutool.core.net.URLUtil; import cn.hutool.core.text.StrUtil; diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/ClassScanerTest.java b/hutool-core/src/test/java/cn/hutool/core/reflect/ClassScanerTest.java similarity index 88% rename from hutool-core/src/test/java/cn/hutool/core/lang/ClassScanerTest.java rename to hutool-core/src/test/java/cn/hutool/core/reflect/ClassScanerTest.java index 68b20c007..8a2b9cd98 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/ClassScanerTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/reflect/ClassScanerTest.java @@ -1,5 +1,7 @@ -package cn.hutool.core.lang; +package cn.hutool.core.reflect; +import cn.hutool.core.lang.Console; +import cn.hutool.core.reflect.ClassScanner; import org.junit.Ignore; import org.junit.Test; From 7318402204ba138c65813296d71bf5501a110295 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 20 Sep 2022 18:56:17 +0800 Subject: [PATCH 20/73] fix code --- .../src/main/java/cn/hutool/core/util/EnumUtil.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java index 220fd4762..03f31f47a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java @@ -248,6 +248,18 @@ public class EnumUtil { return Arrays.stream(implClass.getEnumConstants()).filter(e -> condition.apply(e).equals(value)).findAny().orElse(null); } + /** + * 通过 某字段对应值 获取 枚举,获取不到时为 {@code defaultEnum} + * + * @param condition 条件字段 + * @param value 条件字段值 + * @param defaultEnum 条件找不到则返回结果使用这个 + * @return 对应枚举 ,获取不到时为 {@code null} + */ + public static , C> E getBy(final SerFunction condition, final C value, final E defaultEnum) { + return ObjUtil.defaultIfNull(getBy(condition,value), defaultEnum); + } + /** * 通过 某字段对应值 获取 枚举中另一字段值,获取不到时为 {@code null} * From f62a36b045687fa68c4780a8723fa738a412cd0b Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 20 Sep 2022 23:02:33 +0800 Subject: [PATCH 21/73] fix bug --- .../java/cn/hutool/core/codec/PunyCode.java | 6 +++++- .../cn/hutool/core/codec/PunyCodeTest.java | 19 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java b/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java index babe8a98f..ddc441b50 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java @@ -85,6 +85,10 @@ public class PunyCode { } // Append delimiter if (b > 0) { + if(b == length){ + // 无需要编码的字符 + return output.toString(); + } output.append(DELIMITER); } int h = b; @@ -158,7 +162,7 @@ public class PunyCode { if (result.length() != 0) { result.append(CharUtil.DOT); } - result.append(decode(str)); + result.append(StrUtil.startWithIgnoreEquals(str, PUNY_CODE_PREFIX) ? decode(str) : str); } return result.toString(); diff --git a/hutool-core/src/test/java/cn/hutool/core/codec/PunyCodeTest.java b/hutool-core/src/test/java/cn/hutool/core/codec/PunyCodeTest.java index 95d267ffe..3193ade29 100644 --- a/hutool-core/src/test/java/cn/hutool/core/codec/PunyCodeTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/codec/PunyCodeTest.java @@ -16,6 +16,14 @@ public class PunyCodeTest { Assert.assertEquals(text, decode); } + @Test + public void encodeDecodeTest2(){ + // 无需编码和解码 + String text = "Hutool"; + String strPunyCode = PunyCode.encode(text); + Assert.assertEquals("Hutool", strPunyCode); + } + @Test public void encodeDecodeDomainTest() { // 全中文 @@ -32,7 +40,7 @@ public class PunyCodeTest { // 中英文分段 final String text = "hutool.中国"; final String strPunyCode = PunyCode.encodeDomain(text); - Assert.assertEquals("xn--hutool-.xn--fiqs8s", strPunyCode); + Assert.assertEquals("hutool.xn--fiqs8s", strPunyCode); final String decode = PunyCode.decodeDomain(strPunyCode); Assert.assertEquals(text, decode); @@ -48,4 +56,13 @@ public class PunyCodeTest { final String decode = PunyCode.decodeDomain(strPunyCode); Assert.assertEquals(text, decode); } + + @Test + public void encodeEncodeDomainTest2(){ + String domain = "赵新虎.com"; + String strPunyCode = PunyCode.encodeDomain(domain); + Assert.assertEquals("xn--efvz93e52e.com", strPunyCode); + String decode = PunyCode.decodeDomain(strPunyCode); + Assert.assertEquals(domain, decode); + } } From 400a7b7e040a7471ab37ed526ef4f9767108802f Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 21 Sep 2022 21:48:06 +0800 Subject: [PATCH 22/73] add method --- .../cn/hutool/core/reflect/ModifierUtil.java | 53 +++++++++++++++++++ .../cn/hutool/core/util/ModifierUtilTest.java | 27 ++++++++++ 2 files changed, 80 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/ModifierUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ModifierUtil.java index 9560e564e..694489028 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/ModifierUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ModifierUtil.java @@ -1,7 +1,9 @@ package cn.hutool.core.reflect; +import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.util.ArrayUtil; +import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Modifier; @@ -213,6 +215,57 @@ public class ModifierUtil { public static boolean isInterface(final Class clazz) { return null != clazz && clazz.isInterface(); } + + /** + * 设置final的field字段可以被修改 + * 只要不会被编译器内联优化的 final 属性就可以通过反射有效的进行修改 -- 修改后代码中可使用到新的值; + *

以下属性,编译器会内联优化,无法通过反射修改:

+ *
    + *
  • 基本类型 byte, char, short, int, long, float, double, boolean
  • + *
  • Literal String 类型(直接双引号字符串)
  • + *
+ *

以下属性,可以通过反射修改:

+ *
    + *
  • 基本类型的包装类 Byte、Character、Short、Long、Float、Double、Boolean
  • + *
  • 字符串,通过 new String("")实例化
  • + *
  • 自定义java类
  • + *
+ *
+	 * {@code
+	 *      //示例,移除final修饰符
+	 *      class JdbcDialects {private static final List dialects = new ArrayList<>();}
+	 *      Field field = ReflectUtil.getField(JdbcDialects.class, fieldName);
+	 * 		ReflectUtil.removeFinalModify(field);
+	 * 		ReflectUtil.setFieldValue(JdbcDialects.class, fieldName, dialects);
+	 *    }
+	 * 
+ * + * @param field 被修改的field,不可以为空 + * @throws UtilException IllegalAccessException等异常包装 + * @author dazer + * @since 5.8.8 + */ + public static void removeFinalModify(final Field field) { + if (null == field || false == hasModifier(field, ModifierUtil.ModifierType.FINAL)) { + return; + } + //将字段的访问权限设为true:即去除private修饰符的影响 + if (false == field.isAccessible()) { + field.setAccessible(true); + } + try { + //去除final修饰符的影响,将字段设为可修改的 + final Field modifiersField = Field.class.getDeclaredField("modifiers"); + //Field 的 modifiers 是私有的 + modifiersField.setAccessible(true); + //& :位与运算符,按位与; 运算规则:两个数都转为二进制,然后从高位开始比较,如果两个数都为1则为1,否则为0。 + //~ :位非运算符,按位取反;运算规则:转成二进制,如果位为0,结果是1,如果位为1,结果是0. + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + } catch (final NoSuchFieldException | IllegalAccessException e) { + //内部,工具类,基本不抛出异常 + throw new UtilException(e, "IllegalAccess for {}.{}", field.getDeclaringClass(), field.getName()); + } + } //-------------------------------------------------------------------------------------------------------- Private method start /** diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ModifierUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ModifierUtilTest.java index fae64188a..a7385ce13 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/ModifierUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ModifierUtilTest.java @@ -1,10 +1,14 @@ package cn.hutool.core.util; +import cn.hutool.core.reflect.FieldUtil; import cn.hutool.core.reflect.ModifierUtil; import org.junit.Assert; import org.junit.Test; +import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; public class ModifierUtilTest { @@ -20,4 +24,27 @@ public class ModifierUtilTest { private static void ddd() { } + + @Test + public void setFinalFieldValueTest() { + final String fieldName = "DIALECTS"; + final List dialects = + Arrays.asList( + 1, + 2, + 3, + 99 + ); + final Field field = FieldUtil.getField(JdbcDialects.class, fieldName); + ModifierUtil.removeFinalModify(field); + FieldUtil.setFieldValue(JdbcDialects.class, fieldName, dialects); + + Assert.assertEquals(dialects, FieldUtil.getFieldValue(JdbcDialects.class, fieldName)); + } + + @SuppressWarnings("unused") + public static class JdbcDialects { + private static final List DIALECTS = + Arrays.asList(1L, 2L, 3L); + } } From b13329d7819238e3ce349e395fcbc1940cfbc66e Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 21 Sep 2022 22:04:47 +0800 Subject: [PATCH 23/73] fix code --- .../cn/hutool/core/stream/CollectorUtil.java | 2 +- .../cn/hutool/core/stream/EntryStream.java | 62 ++++++++++--------- .../stream/TransformableWrappedStream.java | 4 +- .../cn/hutool/core/stream/package-info.java | 3 +- .../spliterators/DropWhileSpliterator.java | 6 +- .../spliterators/IterateSpliterator.java | 10 +-- .../spliterators/TakeWhileSpliterator.java | 6 +- 7 files changed, 47 insertions(+), 46 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 1dcc72096..ecbfab5a7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -277,7 +277,7 @@ public class CollectorUtil { * @since 6.0.0 */ public static Collector, EntryStream> toEntryStream( - Function keyMapper) { + final Function keyMapper) { return toEntryStream(keyMapper, Function.identity()); } diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EntryStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EntryStream.java index dff2c8801..f712f40fd 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EntryStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EntryStream.java @@ -38,7 +38,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream 值类型 * @param keys 键集合 * @param values 值集合 - * @return {@link EntryStream}实例 + * @return {@code EntryStream}实例 */ public static EntryStream merge(final Iterable keys, final Iterable values) { final boolean hasKeys = ObjUtil.isNotNull(keys); @@ -75,7 +75,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream 键类型 * @param 值类型 - * @return {@link EntryStream}实例 + * @return {@code EntryStream}实例 */ public static EntryStream of(final Map map) { return ObjUtil.isNull(map) ? @@ -90,7 +90,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream 键类型 * @param 值类型 - * @return {@link EntryStream}实例 + * @return {@code EntryStream}实例 */ public static EntryStream of(final Iterable> entries) { return ObjUtil.isNull(entries) ? @@ -106,10 +106,10 @@ public class EntryStream extends AbstractEnhancedWrappedStream 元素类型 * @param 键类型 * @param 值类型 - * @return {@link EntryStream}实例 + * @return {@code EntryStream}实例 */ public static EntryStream of( - final Iterable source, Function keyMapper, Function valueMapper) { + final Iterable source, final Function keyMapper, final Function valueMapper) { Objects.requireNonNull(keyMapper); Objects.requireNonNull(valueMapper); if (ObjUtil.isNull(source)) { @@ -127,9 +127,9 @@ public class EntryStream extends AbstractEnhancedWrappedStream 键类型 * @param 值类型 - * @return {@link EntryStream}实例 + * @return {@code EntryStream}实例 */ - public static EntryStream of(Stream> stream) { + public static EntryStream of(final Stream> stream) { return ObjUtil.isNull(stream) ? empty() : new EntryStream<>(stream.map(EntryStream::ofEntry)); } @@ -139,7 +139,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream 键类型 * @param 值类型 - * @return {@link EntryStream}实例 + * @return {@code EntryStream}实例 */ public static EntryStream empty() { return new EntryStream<>(Stream.empty()); @@ -157,7 +157,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream distinctByKey() { // FIXME fix happen NPE when has null key @@ -175,7 +175,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream distinctByValue() { // FIXME fix happen NPE when has null value @@ -194,7 +194,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream filter(final BiPredicate filter) { Objects.requireNonNull(filter); @@ -205,7 +205,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream filterByKey(final Predicate filter) { Objects.requireNonNull(filter); @@ -216,7 +216,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream filterByValue(final Predicate filter) { Objects.requireNonNull(filter); @@ -226,7 +226,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream nonNullKeyValue() { return super.filter(e -> ObjUtil.isNotNull(e) && ObjUtil.isNotNull(e.getKey()) && ObjUtil.isNotNull(e.getValue())); @@ -235,7 +235,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream nonNullKey() { return super.filter(e -> ObjUtil.isNotNull(e) && ObjUtil.isNotNull(e.getKey())); @@ -244,7 +244,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream nonNullValue() { return super.filter(e -> ObjUtil.isNotNull(e) && ObjUtil.isNotNull(e.getValue())); @@ -254,7 +254,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream peekKey(final Consumer consumer) { Objects.requireNonNull(consumer); @@ -265,7 +265,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream peekValue(final Consumer consumer) { Objects.requireNonNull(consumer); @@ -276,7 +276,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream sortByKey(final Comparator comparator) { Objects.requireNonNull(comparator); @@ -287,7 +287,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream sortByValue(final Comparator comparator) { Objects.requireNonNull(comparator); @@ -301,7 +301,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream push(final K key, final V value) { return wrap(Stream.concat(stream, Stream.of(ofEntry(key, value)))); @@ -312,7 +312,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream unshift(final K key, final V value) { return wrap(Stream.concat(Stream.of(ofEntry(key, value)), stream)); @@ -322,7 +322,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream append(final Iterable> entries) { @@ -338,7 +338,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream prepend(final Iterable> entries) { @@ -373,7 +373,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream 新的键类型 - * @return {@link EntryStream}实例 + * @return {@code EntryStream}实例 */ public EntryStream mapKeys(final Function mapper) { Objects.requireNonNull(mapper); @@ -387,7 +387,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream 新的值类型 - * @return {@link EntryStream}实例 + * @return {@code EntryStream}实例 */ public EntryStream mapValues(final Function mapper) { Objects.requireNonNull(mapper); @@ -442,7 +442,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream将原有流的键执行mapper操作映射为流,流中的所有所有元素仍然对应原本的值, - * 然后再返回由这些流中所有元素组成的流新{@link EntryStream}串行流。
+ * 然后再返回由这些流中所有元素组成的流新{@code EntryStream}串行流。
* 效果类似: *
{@code
 	 * // unwrap = [{a = 1}, {b = 2}, {c = 3}]
@@ -466,7 +466,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream将原有流的值执行mapper操作映射为流,流中的所有所有元素仍然对应原本的键,
-	 * 然后再返回由这些流中所有元素组成的流新{@link EntryStream}串行流。
+ * 然后再返回由这些流中所有元素组成的流新{@code EntryStream}串行流。
* 效果类似: *
{@code
 	 * // unwrap = [{a = 1}, {b = 2}, {c = 3}]
@@ -664,7 +664,7 @@ public class EntryStream extends AbstractEnhancedWrappedStream inverse() {
 		return new EntryStream<>(
@@ -760,7 +760,9 @@ public class EntryStream extends AbstractEnhancedWrappedStream BinaryOperator throwingMerger() {
-		return (u, v) -> {throw new IllegalStateException(String.format("Duplicate key %s", u));};
+		return (u, v) -> {
+			throw new IllegalStateException(String.format("Duplicate key %s", u));
+		};
 	}
 
 }
diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/TransformableWrappedStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/TransformableWrappedStream.java
index d209d63dc..3272b9bd0 100644
--- a/hutool-core/src/main/java/cn/hutool/core/stream/TransformableWrappedStream.java
+++ b/hutool-core/src/main/java/cn/hutool/core/stream/TransformableWrappedStream.java
@@ -51,8 +51,8 @@ public interface TransformableWrappedStream other,
 			final BiFunction zipper) {
 		Objects.requireNonNull(zipper);
-		Map idxIdentityMap = mapIdx((e, idx) -> MapUtil.entry(idx, e)).collect(CollectorUtil.entryToMap());
-		Map idxOtherMap = EasyStream.of(other).mapIdx((e, idx) -> MapUtil.entry(idx, e)).collect(CollectorUtil.entryToMap());
+		final Map idxIdentityMap = mapIdx((e, idx) -> MapUtil.entry(idx, e)).collect(CollectorUtil.entryToMap());
+		final Map idxOtherMap = EasyStream.of(other).mapIdx((e, idx) -> MapUtil.entry(idx, e)).collect(CollectorUtil.entryToMap());
 		if (idxIdentityMap.size() <= idxOtherMap.size()) {
 			return EasyStream.of(idxIdentityMap.keySet(), isParallel()).map(k -> zipper.apply(idxIdentityMap.get(k), idxOtherMap.get(k)));
 		}
diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/package-info.java b/hutool-core/src/main/java/cn/hutool/core/stream/package-info.java
index 155cf24db..dadfa3d59 100644
--- a/hutool-core/src/main/java/cn/hutool/core/stream/package-info.java
+++ b/hutool-core/src/main/java/cn/hutool/core/stream/package-info.java
@@ -1,7 +1,6 @@
 /**
  * Java8的stream相关封装
  *
- * @author looly
- *
+ * @author Looly, VampireAchao, huangchengxing, emptypoint
  */
 package cn.hutool.core.stream;
diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/DropWhileSpliterator.java b/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/DropWhileSpliterator.java
index 4bb620670..da50ee216 100644
--- a/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/DropWhileSpliterator.java
+++ b/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/DropWhileSpliterator.java
@@ -14,7 +14,7 @@ import java.util.function.Predicate;
  */
 public class DropWhileSpliterator implements Spliterator {
 
-	public static  DropWhileSpliterator create(Spliterator source, Predicate predicate) {
+	public static  DropWhileSpliterator create(final Spliterator source, final Predicate predicate) {
 		return new DropWhileSpliterator<>(source, predicate);
 	}
 
@@ -22,13 +22,13 @@ public class DropWhileSpliterator implements Spliterator {
 	private final Predicate predicate;
 	private boolean isFound = false;
 
-	private DropWhileSpliterator(Spliterator source, Predicate predicate) {
+	private DropWhileSpliterator(final Spliterator source, final Predicate predicate) {
 		this.source = source;
 		this.predicate = predicate;
 	}
 
 	@Override
-	public boolean tryAdvance(Consumer action) {
+	public boolean tryAdvance(final Consumer action) {
 		boolean hasNext = true;
 		// 如果 还没找到 并且 流中还有元素 继续找
 		while (!isFound && hasNext) {
diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/IterateSpliterator.java b/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/IterateSpliterator.java
index edf2170f5..9a2d37642 100644
--- a/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/IterateSpliterator.java
+++ b/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/IterateSpliterator.java
@@ -25,24 +25,24 @@ public class IterateSpliterator extends Spliterators.AbstractSpliterator {
 	 * Creates a spliterator reporting the given estimated size and
 	 * additionalCharacteristics.
 	 */
-	IterateSpliterator(T seed, Predicate hasNext, UnaryOperator next) {
+	IterateSpliterator(final T seed, final Predicate hasNext, final UnaryOperator next) {
 		super(Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.IMMUTABLE);
 		this.seed = seed;
 		this.hasNext = hasNext;
 		this.next = next;
 	}
 
-	public static  IterateSpliterator create(T seed, Predicate hasNext, UnaryOperator next) {
+	public static  IterateSpliterator create(final T seed, final Predicate hasNext, final UnaryOperator next) {
 		return new IterateSpliterator<>(seed, hasNext, next);
 	}
 
 	@Override
-	public boolean tryAdvance(Consumer action) {
+	public boolean tryAdvance(final Consumer action) {
 		Objects.requireNonNull(action);
 		if (finished) {
 			return false;
 		}
-		T t;
+		final T t;
 		if (started) {
 			t = next.apply(prev);
 		} else {
@@ -60,7 +60,7 @@ public class IterateSpliterator extends Spliterators.AbstractSpliterator {
 	}
 
 	@Override
-	public void forEachRemaining(Consumer action) {
+	public void forEachRemaining(final Consumer action) {
 		Objects.requireNonNull(action);
 		if (finished) {
 			return;
diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/TakeWhileSpliterator.java b/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/TakeWhileSpliterator.java
index 318e33351..3313cd285 100644
--- a/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/TakeWhileSpliterator.java
+++ b/hutool-core/src/main/java/cn/hutool/core/stream/spliterators/TakeWhileSpliterator.java
@@ -14,7 +14,7 @@ import java.util.function.Predicate;
  */
 public class TakeWhileSpliterator implements Spliterator {
 
-	public static  TakeWhileSpliterator create(Spliterator source, Predicate predicate) {
+	public static  TakeWhileSpliterator create(final Spliterator source, final Predicate predicate) {
 		return new TakeWhileSpliterator<>(source, predicate);
 	}
 
@@ -22,13 +22,13 @@ public class TakeWhileSpliterator implements Spliterator {
 	private final Predicate predicate;
 	private boolean isContinue = true;
 
-	TakeWhileSpliterator(Spliterator source, Predicate predicate) {
+	TakeWhileSpliterator(final Spliterator source, final Predicate predicate) {
 		this.source = source;
 		this.predicate = predicate;
 	}
 
 	@Override
-	public boolean tryAdvance(Consumer action) {
+	public boolean tryAdvance(final Consumer action) {
 		boolean hasNext = true;
 		// 如果 还可以继续 并且 流中还有元素 则继续遍历
 		while (isContinue && hasNext) {

From f2629f775b264c38ad0e07da8441608a86516fa1 Mon Sep 17 00:00:00 2001
From: Looly 
Date: Thu, 22 Sep 2022 02:31:28 +0800
Subject: [PATCH 24/73] =?UTF-8?q?=E7=B2=BE=E7=AE=80XXXTypeGetter?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../cn/hutool/core/collection/ListUtil.java   |   5 +-
 .../java/cn/hutool/core/convert/Convert.java  |   7 +-
 .../hutool/core/io/resource/ResourceUtil.java |  23 +
 .../core/lang/getter/ArrayTypeGetter.java     | 102 ----
 .../core/lang/getter/BasicTypeGetter.java     | 130 -----
 .../core/lang/getter/GroupedTypeGetter.java   | 243 +++++++-
 .../core/lang/getter/ListTypeGetter.java      | 102 ----
 .../core/lang/getter/OptArrayTypeGetter.java  | 117 ----
 .../core/lang/getter/OptBasicTypeGetter.java  | 153 -----
 .../OptNullBasicTypeFromObjectGetter.java     | 133 -----
 .../OptNullBasicTypeFromStringGetter.java     |  80 ---
 .../lang/getter/OptNullBasicTypeGetter.java   | 176 ------
 .../hutool/core/lang/getter/TypeGetter.java   | 529 ++++++++++++++++++
 .../main/java/cn/hutool/core/map/Dict.java    | 160 +-----
 .../java/cn/hutool/core/map/MapProxy.java     |  14 +-
 .../hutool/core/map/multi/ListValueMap.java   |   4 +-
 .../cn/hutool/core/text/CharSequenceUtil.java |   1 -
 .../hutool/core/collection/MapProxyTest.java  |  10 +-
 .../cn/hutool/core/convert/ConvertTest.java   |   2 +
 .../AbstractEnhancedWrappedStreamTest.java    |  59 +-
 .../src/main/java/cn/hutool/db/Entity.java    |  32 +-
 .../cn/hutool/db/ds/AbstractDSFactory.java    |   8 +-
 .../cn/hutool/db/ds/bee/BeeDSFactory.java     |   2 +-
 .../cn/hutool/db/ds/c3p0/C3p0DSFactory.java   |   2 +-
 .../cn/hutool/db/ds/dbcp/DbcpDSFactory.java   |   2 +-
 .../cn/hutool/db/ds/druid/DruidDSFactory.java |   2 +-
 .../hutool/db/ds/hikari/HikariDSFactory.java  |   2 +-
 .../cn/hutool/db/ds/pooled/DbSetting.java     |  16 +-
 .../hutool/db/ds/simple/SimpleDataSource.java |   8 +-
 .../hutool/db/ds/tomcat/TomcatDSFactory.java  |   2 +-
 .../main/java/cn/hutool/json/JSONConfig.java  |   2 +-
 .../main/java/cn/hutool/json/JSONGetter.java  |  51 +-
 .../java/cn/hutool/setting/AbsSetting.java    | 230 ++------
 .../java/cn/hutool/setting/GroupedMap.java    |   4 +-
 .../main/java/cn/hutool/setting/Setting.java  |  86 +--
 .../java/cn/hutool/setting/dialect/Props.java | 285 +---------
 .../java/cn/hutool/setting/PropsTest.java     |   8 +-
 .../java/cn/hutool/setting/SettingTest.java   |  12 +-
 .../cn/hutool/setting/SettingUtilTest.java    |   6 +-
 39 files changed, 969 insertions(+), 1841 deletions(-)
 delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/ArrayTypeGetter.java
 delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/BasicTypeGetter.java
 delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/ListTypeGetter.java
 delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/OptArrayTypeGetter.java
 delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/OptBasicTypeGetter.java
 delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeFromObjectGetter.java
 delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeFromStringGetter.java
 delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeGetter.java
 create mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/getter/TypeGetter.java

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 48811aabc..10ac0d8b0 100755
--- a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java
@@ -177,7 +177,8 @@ public class ListUtil {
 
 	/**
 	 * 数组转为一个不可变List
- * 类似于Java9中的List.of + * 类似于Java9中的List.of
+ * 不同于Arrays.asList,此方法的原数组修改时,并不会影响List。 * * @param ts 对象 * @param 对象类型 @@ -708,7 +709,7 @@ public class ListUtil { * @since 6.0.0 */ @SafeVarargs - public static List splice(List list, int start, int deleteCount, T... items) { + public static List splice(final List list, int start, int deleteCount, final T... items) { if (CollUtil.isEmpty(list)) { return zero(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java b/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java index f4eecb3ba..6785f406c 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/Convert.java @@ -533,7 +533,7 @@ public class Convert { @SuppressWarnings("unchecked") public static > E toEnum(final Class clazz, final Object value, final E defaultValue) { try{ - return (E) (new EnumConverter()).convert(clazz, value); + return (E) EnumConverter.INSTANCE.convert(clazz, value); } catch (final Exception ignore){ return defaultValue; } @@ -615,7 +615,7 @@ public class Convert { * @return {@link Map} * @since 4.6.8 */ - public static Map toMap(Class keyType, Class valueType, Object value) { + public static Map toMap(final Class keyType, final Class valueType, final Object value) { if (value instanceof Map) { return toMap(value.getClass(), keyType, valueType, value); } else { @@ -635,7 +635,7 @@ public class Convert { * @return {@link Map} */ @SuppressWarnings({"unchecked"}) - public static Map toMap(Class mapType, Class keyType, Class valueType, Object value) { + public static Map toMap(final Class mapType, final Class keyType, final Class valueType, final Object value) { return (Map) MapConverter.INSTANCE.convert(mapType, keyType, valueType, value); } @@ -1049,7 +1049,6 @@ public class Convert { /** * 中文大写数字金额转换为数字,返回结果以元为单位的BigDecimal类型数字 - * * 如: * “陆万柒仟伍佰伍拾陆元叁角贰分”返回“67556.32” * “叁角贰分”返回“0.32” diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java index 124f35f0e..ceb52f1c8 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java @@ -10,6 +10,7 @@ import cn.hutool.core.text.StrUtil; import cn.hutool.core.net.URLUtil; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -210,4 +211,26 @@ public class ResourceUtil { } return new ClassPathResource(path); } + + /** + * 获取{@link UrlResource} 资源对象 + * + * @param url URL + * @return {@link Resource} 资源对象 + * @since 6.0.0 + */ + public static Resource getResource(final URL url) { + return new UrlResource(url); + } + + /** + * 获取{@link FileResource} 资源对象 + * + * @param file {@link File} + * @return {@link Resource} 资源对象 + * @since 6.0.0 + */ + public static Resource getResource(final File file) { + return new FileResource(file); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/ArrayTypeGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/ArrayTypeGetter.java deleted file mode 100644 index 5ffddd0a7..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/ArrayTypeGetter.java +++ /dev/null @@ -1,102 +0,0 @@ -package cn.hutool.core.lang.getter; - -import java.math.BigDecimal; -import java.math.BigInteger; - -/** - * 数组类型的Get接口 - * @author Looly - * - */ -public interface ArrayTypeGetter { - /*-------------------------- 数组类型 start -------------------------------*/ - - /** - * 获取Object型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - String[] getObjs(String key); - - /** - * 获取String型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - String[] getStrs(String key); - - /** - * 获取Integer型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - Integer[] getInts(String key); - - /** - * 获取Short型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - Short[] getShorts(String key); - - /** - * 获取Boolean型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - Boolean[] getBools(String key); - - /** - * 获取Long型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - Long[] getLongs(String key); - - /** - * 获取Character型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - Character[] getChars(String key); - - /** - * 获取Double型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - Double[] getDoubles(String key); - - /** - * 获取Byte型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - Byte[] getBytes(String key); - - /** - * 获取BigInteger型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - BigInteger[] getBigIntegers(String key); - - /** - * 获取BigDecimal型属性值数组 - * - * @param key 属性名 - * @return 属性值列表 - */ - BigDecimal[] getBigDecimals(String key); - /*-------------------------- 数组类型 end -------------------------------*/ -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/BasicTypeGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/BasicTypeGetter.java deleted file mode 100644 index de41bdb2d..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/BasicTypeGetter.java +++ /dev/null @@ -1,130 +0,0 @@ -package cn.hutool.core.lang.getter; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Date; - -/** - * 基本类型的getter接口
- * 提供一个统一的接口定义返回不同类型的值(基本类型)
- * - * @author Looly - */ -public interface BasicTypeGetter { - /*-------------------------- 基本类型 start -------------------------------*/ - - /** - * 获取Object属性值 - * - * @param key 属性名 - * @return 属性值 - */ - Object getObj(K key); - - /** - * 获取字符串型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - String getStr(K key); - - /** - * 获取int型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - Integer getInt(K key); - - /** - * 获取short型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - Short getShort(K key); - - /** - * 获取boolean型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - Boolean getBool(K key); - - /** - * 获取long型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - Long getLong(K key); - - /** - * 获取char型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - Character getChar(K key); - - /** - * 获取float型属性值
- * - * @param key 属性名 - * @return 属性值 - */ - Float getFloat(K key); - - /** - * 获取double型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - Double getDouble(K key); - - /** - * 获取byte型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - Byte getByte(K key); - - /** - * 获取BigDecimal型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - BigDecimal getBigDecimal(K key); - - /** - * 获取BigInteger型属性值 - * - * @param key 属性名 - * @return 属性值 - */ - BigInteger getBigInteger(K key); - - /** - * 获得Enum类型的值 - * - * @param 枚举类型 - * @param clazz Enum的Class - * @param key KEY - * @return Enum类型的值,无则返回Null - */ - > E getEnum(Class clazz, K key); - - /** - * 获取Date类型值 - * - * @param key 属性名 - * @return Date类型属性值 - */ - Date getDate(K key); - /*-------------------------- 基本类型 end -------------------------------*/ -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/GroupedTypeGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/GroupedTypeGetter.java index 506ca7205..5d1fc42e5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/GroupedTypeGetter.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/getter/GroupedTypeGetter.java @@ -1,103 +1,296 @@ package cn.hutool.core.lang.getter; +import cn.hutool.core.convert.Convert; + +import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; /** * 基于分组的Get接口 - * @author Looly * + * @param 键类型 + * @param 分组键类型 + * @author Looly + * @since 6.0.0 */ -public interface GroupedTypeGetter { - /*-------------------------- 基本类型 start -------------------------------*/ +public interface GroupedTypeGetter { + /** - * 获取字符串型属性值
+ * 获取Object属性值,最原始的对象获取,没有任何转换或类型判断 * - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + Object getObjByGroup(K key, G group, Object defaultValue); + + /** + * 获取Object属性值,最原始的对象获取,没有任何转换或类型判断 + * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - String getStrByGroup(String key, String group); + default Object getObjByGroup(final K key, final G group) { + return getObjByGroup(key, group, null); + } + + /** + * 获取指定类型的值,默认自动转换值类型 + * + * @param 目标类型 + * @param key 键 + * @param group 分组 + * @param type 目标类型 + * @return 结果值 + */ + default T getByGroup(final K key, final G group, final Type type) { + return getByGroup(key, group, type, null); + } + + /** + * 获取指定类型的值,默认自动转换值类型 + * + * @param 目标类型 + * @param key 键 + * @param group 分组 + * @param type 目标类型 + * @param defaultValue 默认值 + * @return 结果值 + */ + default T getByGroup(final K key, final G group, final Type type, final T defaultValue) { + return Convert.convert(type, getObjByGroup(key, group), defaultValue); + } + + /** + * 获取字符串型属性值 + * + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default String getStrByGroup(final K key, final G group, final String defaultValue) { + return getByGroup(key, group, String.class, defaultValue); + } + + /** + * 获取字符串型属性值 + * + * @param key 属性名 + * @param group 分组 + * @return 属性值 + */ + default String getStrByGroup(final K key, final G group) { + return getStrByGroup(key, group, null); + } /** * 获取int型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default Integer getIntByGroup(final K key, final G group, final Integer defaultValue) { + return getByGroup(key, group, Integer.class, defaultValue); + } + + /** + * 获取int型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - Integer getIntByGroup(String key, String group); + default Integer getIntByGroup(final K key, final G group) { + return getIntByGroup(key, group, null); + } /** * 获取short型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default Short getShortByGroup(final K key, final G group, final Short defaultValue) { + return getByGroup(key, group, Short.class, defaultValue); + } + + /** + * 获取short型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - Short getShortByGroup(String key, String group); + default Short getShortByGroup(final K key, final G group) { + return getShortByGroup(key, group, null); + } /** * 获取boolean型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default Boolean getBoolByGroup(final K key, final G group, final Boolean defaultValue) { + return getByGroup(key, group, Boolean.class, defaultValue); + } + + /** + * 获取boolean型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - Boolean getBoolByGroup(String key, String group); + default Boolean getBoolByGroup(final K key, final G group) { + return getBoolByGroup(key, group, null); + } /** * 获取Long型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default Long getLongByGroup(final K key, final G group, final Long defaultValue) { + return getByGroup(key, group, Long.class, defaultValue); + } + + /** + * 获取Long型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - Long getLongByGroup(String key, String group); + default Long getLongByGroup(final K key, final G group) { + return getLongByGroup(key, group, null); + } /** * 获取char型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default Character getCharByGroup(final K key, final G group, final Character defaultValue) { + return getByGroup(key, group, Character.class, defaultValue); + } + + /** + * 获取char型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - Character getCharByGroup(String key, String group); + default Character getCharByGroup(final K key, final G group) { + return getCharByGroup(key, group, null); + } /** * 获取double型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default Double getDoubleByGroup(final K key, final G group, final Double defaultValue) { + return getByGroup(key, group, Double.class, defaultValue); + } + + /** + * 获取double型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - Double getDoubleByGroup(String key, String group); + default Double getDoubleByGroup(final K key, final G group) { + return getDoubleByGroup(key, group, null); + } /** * 获取byte型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default Byte getByteByGroup(final K key, final G group, final Byte defaultValue) { + return getByGroup(key, group, Byte.class, defaultValue); + } + + /** + * 获取byte型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - Byte getByteByGroup(String key, String group); + default Byte getByteByGroup(final K key, final G group) { + return getByteByGroup(key, group, null); + } /** * 获取BigDecimal型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default BigDecimal getBigDecimalByGroup(final K key, final G group, final BigDecimal defaultValue) { + return getByGroup(key, group, BigDecimal.class, defaultValue); + } + + /** + * 获取BigDecimal型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - BigDecimal getBigDecimalByGroup(String key, String group); + default BigDecimal getBigDecimalByGroup(final K key, final G group) { + return getBigDecimalByGroup(key, group, null); + } /** * 获取BigInteger型属性值
* - * @param key 属性名 + * @param key 属性名 + * @param group 分组 + * @param defaultValue 默认值 + * @return 属性值 + */ + default BigInteger getBigIntegerByGroup(final K key, final G group, final BigInteger defaultValue) { + return getByGroup(key, group, BigInteger.class, defaultValue); + } + + /** + * 获取BigInteger型属性值
+ * + * @param key 属性名 * @param group 分组 * @return 属性值 */ - BigInteger getBigIntegerByGroup(String key, String group); - /*-------------------------- 基本类型 end -------------------------------*/ + default BigInteger getBigIntegerByGroup(final K key, final G group) { + return getBigIntegerByGroup(key, group, null); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/ListTypeGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/ListTypeGetter.java deleted file mode 100644 index 4f7c25d2b..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/ListTypeGetter.java +++ /dev/null @@ -1,102 +0,0 @@ -package cn.hutool.core.lang.getter; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.List; - -/** - * 列表类型的Get接口 - * @author Looly - * - */ -public interface ListTypeGetter { - /*-------------------------- List类型 start -------------------------------*/ - /** - * 获取Object型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getObjList(String key); - - /** - * 获取String型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getStrList(String key); - - /** - * 获取Integer型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getIntList(String key); - - /** - * 获取Short型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getShortList(String key); - - /** - * 获取Boolean型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getBoolList(String key); - - /** - * 获取Long型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getLongList(String key); - - /** - * 获取Character型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getCharList(String key); - - /** - * 获取Double型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getDoubleList(String key); - - /** - * 获取Byte型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getByteList(String key); - - /** - * 获取BigDecimal型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getBigDecimalList(String key); - - /** - * 获取BigInteger型属性值列表 - * - * @param key 属性名 - * @return 属性值列表 - */ - List getBigIntegerList(String key); - /*-------------------------- List类型 end -------------------------------*/ -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptArrayTypeGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptArrayTypeGetter.java deleted file mode 100644 index ecec0526f..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptArrayTypeGetter.java +++ /dev/null @@ -1,117 +0,0 @@ -package cn.hutool.core.lang.getter; - -import java.math.BigDecimal; -import java.math.BigInteger; - -/** - * 可选默认值的数组类型的Get接口 - * 提供一个统一的接口定义返回不同类型的值(基本类型)
- * 如果值不存在或获取错误,返回默认值 - * - * @author Looly - * @since 4.0.2 - * - */ -public interface OptArrayTypeGetter { - /*-------------------------- 数组类型 start -------------------------------*/ - - /** - * 获取Object型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - Object[] getObjs(String key, Object[] defaultValue); - - /** - * 获取String型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - String[] getStrs(String key, String[] defaultValue); - - /** - * 获取Integer型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - Integer[] getInts(String key, Integer[] defaultValue); - - /** - * 获取Short型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - Short[] getShorts(String key, Short[] defaultValue); - - /** - * 获取Boolean型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - Boolean[] getBools(String key, Boolean[] defaultValue); - - /** - * 获取Long型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - Long[] getLongs(String key, Long[] defaultValue); - - /** - * 获取Character型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - Character[] getChars(String key, Character[] defaultValue); - - /** - * 获取Double型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - Double[] getDoubles(String key, Double[] defaultValue); - - /** - * 获取Byte型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - Byte[] getBytes(String key, Byte[] defaultValue); - - /** - * 获取BigInteger型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - BigInteger[] getBigIntegers(String key, BigInteger[] defaultValue); - - /** - * 获取BigDecimal型属性值数组 - * - * @param key 属性名 - * @param defaultValue 默认数组值 - * @return 属性值列表 - */ - BigDecimal[] getBigDecimals(String key, BigDecimal[] defaultValue); - /*-------------------------- 数组类型 end -------------------------------*/ -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptBasicTypeGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptBasicTypeGetter.java deleted file mode 100644 index 3e405fc7e..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptBasicTypeGetter.java +++ /dev/null @@ -1,153 +0,0 @@ -package cn.hutool.core.lang.getter; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Date; - -/** - * 可选默认值的基本类型的getter接口
- * 提供一个统一的接口定义返回不同类型的值(基本类型)
- * 如果值不存在或获取错误,返回默认值 - * @author Looly - */ -public interface OptBasicTypeGetter { - /*-------------------------- 基本类型 start -------------------------------*/ - - /** - * 获取Object属性值 - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Object getObj(K key, Object defaultValue); - - /** - * 获取字符串型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - String getStr(K key, String defaultValue); - - /** - * 获取int型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Integer getInt(K key, Integer defaultValue); - - /** - * 获取short型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Short getShort(K key, Short defaultValue); - - /** - * 获取boolean型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Boolean getBool(K key, Boolean defaultValue); - - /** - * 获取Long型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Long getLong(K key, Long defaultValue); - - /** - * 获取char型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Character getChar(K key, Character defaultValue); - - /** - * 获取float型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Float getFloat(K key, Float defaultValue); - - /** - * 获取double型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Double getDouble(K key, Double defaultValue); - - /** - * 获取byte型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - Byte getByte(K key, Byte defaultValue); - - /** - * 获取BigDecimal型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - BigDecimal getBigDecimal(K key, BigDecimal defaultValue); - - /** - * 获取BigInteger型属性值
- * 若获得的值为不可见字符,使用默认值 - * - * @param key 属性名 - * @param defaultValue 默认值 - * @return 属性值,无对应值返回defaultValue - */ - BigInteger getBigInteger(K key, BigInteger defaultValue); - - /** - * 获得Enum类型的值 - * - * @param 枚举类型 - * @param clazz Enum的Class - * @param key KEY - * @param defaultValue 默认值 - * @return Enum类型的值,无则返回Null - */ - > E getEnum(Class clazz, K key, E defaultValue); - - /** - * 获取Date类型值 - * @param key 属性名 - * @param defaultValue 默认值 - * @return Date类型属性值 - */ - Date getDate(K key, Date defaultValue); - /*-------------------------- 基本类型 end -------------------------------*/ -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeFromObjectGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeFromObjectGetter.java deleted file mode 100644 index c6c582a19..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeFromObjectGetter.java +++ /dev/null @@ -1,133 +0,0 @@ -package cn.hutool.core.lang.getter; - -import cn.hutool.core.convert.Convert; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Date; - -/** - * 基本类型的getter接口抽象实现,所有类型的值获取都是通过将getObj获得的值转换而来
- * 用户只需实现getObj方法即可,其他类型将会从Object结果中转换 - * 在不提供默认值的情况下, 如果值不存在或获取错误,返回null
- * - * @author Looly - */ -public interface OptNullBasicTypeFromObjectGetter extends OptNullBasicTypeGetter { - @Override - default String getStr(final K key, final String defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toStr(obj, defaultValue); - } - - @Override - default Integer getInt(final K key, final Integer defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toInt(obj, defaultValue); - } - - @Override - default Short getShort(final K key, final Short defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toShort(obj, defaultValue); - } - - @Override - default Boolean getBool(final K key, final Boolean defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toBool(obj, defaultValue); - } - - @Override - default Long getLong(final K key, final Long defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toLong(obj, defaultValue); - } - - @Override - default Character getChar(final K key, final Character defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toChar(obj, defaultValue); - } - - @Override - default Float getFloat(final K key, final Float defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toFloat(obj, defaultValue); - } - - @Override - default Double getDouble(final K key, final Double defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toDouble(obj, defaultValue); - } - - @Override - default Byte getByte(final K key, final Byte defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toByte(obj, defaultValue); - } - - @Override - default BigDecimal getBigDecimal(final K key, final BigDecimal defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toBigDecimal(obj, defaultValue); - } - - @Override - default BigInteger getBigInteger(final K key, final BigInteger defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toBigInteger(obj, defaultValue); - } - - @Override - default > E getEnum(final Class clazz, final K key, final E defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toEnum(clazz, obj, defaultValue); - } - - @Override - default Date getDate(final K key, final Date defaultValue) { - final Object obj = getObj(key); - if (null == obj) { - return defaultValue; - } - return Convert.toDate(obj, defaultValue); - } -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeFromStringGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeFromStringGetter.java deleted file mode 100644 index f4ef35df2..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeFromStringGetter.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.hutool.core.lang.getter; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Date; - -import cn.hutool.core.convert.Convert; - -/** - * 基本类型的getter接口抽象实现,所有类型的值获取都是通过将String转换而来
- * 用户只需实现getStr方法即可,其他类型将会从String结果中转换 在不提供默认值的情况下, 如果值不存在或获取错误,返回null
- * - * @author Looly - */ -public interface OptNullBasicTypeFromStringGetter extends OptNullBasicTypeGetter { - @Override - default Object getObj(final K key, final Object defaultValue) { - return getStr(key, null == defaultValue ? null : defaultValue.toString()); - } - - @Override - default Integer getInt(final K key, final Integer defaultValue) { - return Convert.toInt(getStr(key), defaultValue); - } - - @Override - default Short getShort(final K key, final Short defaultValue) { - return Convert.toShort(getStr(key), defaultValue); - } - - @Override - default Boolean getBool(final K key, final Boolean defaultValue) { - return Convert.toBool(getStr(key), defaultValue); - } - - @Override - default Long getLong(final K key, final Long defaultValue) { - return Convert.toLong(getStr(key), defaultValue); - } - - @Override - default Character getChar(final K key, final Character defaultValue) { - return Convert.toChar(getStr(key), defaultValue); - } - - @Override - default Float getFloat(final K key, final Float defaultValue) { - return Convert.toFloat(getStr(key), defaultValue); - } - - @Override - default Double getDouble(final K key, final Double defaultValue) { - return Convert.toDouble(getStr(key), defaultValue); - } - - @Override - default Byte getByte(final K key, final Byte defaultValue) { - return Convert.toByte(getStr(key), defaultValue); - } - - @Override - default BigDecimal getBigDecimal(final K key, final BigDecimal defaultValue) { - return Convert.toBigDecimal(getStr(key), defaultValue); - } - - @Override - default BigInteger getBigInteger(final K key, final BigInteger defaultValue) { - return Convert.toBigInteger(getStr(key), defaultValue); - } - - @Override - default > E getEnum(final Class clazz, final K key, final E defaultValue) { - return Convert.toEnum(clazz, getStr(key), defaultValue); - } - - @Override - default Date getDate(final K key, final Date defaultValue) { - return Convert.toDate(getStr(key), defaultValue); - } -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeGetter.java deleted file mode 100644 index c52843e8f..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/getter/OptNullBasicTypeGetter.java +++ /dev/null @@ -1,176 +0,0 @@ -package cn.hutool.core.lang.getter; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Date; - -/** - * 基本类型的getter接口抽象实现
- * 提供一个统一的接口定义返回不同类型的值(基本类型)
- * 在不提供默认值的情况下, 如果值不存在或获取错误,返回null
- * 用户只需实现{@link OptBasicTypeGetter}接口即可 - * @author Looly - */ -public interface OptNullBasicTypeGetter extends BasicTypeGetter, OptBasicTypeGetter{ - @Override - default Object getObj(final K key) { - return getObj(key, null); - } - - /** - * 获取字符串型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default String getStr(final K key){ - return this.getStr(key, null); - } - - /** - * 获取int型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Integer getInt(final K key) { - return this.getInt(key, null); - } - - /** - * 获取short型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Short getShort(final K key){ - return this.getShort(key, null); - } - - /** - * 获取boolean型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Boolean getBool(final K key){ - return this.getBool(key, null); - } - - /** - * 获取long型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Long getLong(final K key){ - return this.getLong(key, null); - } - - /** - * 获取char型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Character getChar(final K key){ - return this.getChar(key, null); - } - - /** - * 获取float型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Float getFloat(final K key){ - return this.getFloat(key, null); - } - - /** - * 获取double型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Double getDouble(final K key){ - return this.getDouble(key, null); - } - - /** - * 获取byte型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Byte getByte(final K key){ - return this.getByte(key, null); - } - - /** - * 获取BigDecimal型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default BigDecimal getBigDecimal(final K key){ - return this.getBigDecimal(key, null); - } - - /** - * 获取BigInteger型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default BigInteger getBigInteger(final K key){ - return this.getBigInteger(key, null); - } - - /** - * 获取Enum型属性值
- * 无值或获取错误返回null - * - * @param clazz Enum 的 Class - * @param key 属性名 - * @return 属性值 - */ - @Override - default > E getEnum(final Class clazz, final K key) { - return this.getEnum(clazz, key, null); - } - - /** - * 获取Date型属性值
- * 无值或获取错误返回null - * - * @param key 属性名 - * @return 属性值 - */ - @Override - default Date getDate(final K key) { - return this.getDate(key, null); - } -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/getter/TypeGetter.java b/hutool-core/src/main/java/cn/hutool/core/lang/getter/TypeGetter.java new file mode 100644 index 000000000..7340064c9 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/getter/TypeGetter.java @@ -0,0 +1,529 @@ +package cn.hutool.core.lang.getter; + +import cn.hutool.core.convert.Convert; + +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Time; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Date; + +/** + * 基本类型的getter接口
+ * 提供一个统一的接口定义返回不同类型的值(基本类型),定义类型包括: + *
    + *
  • Object
  • + *
  • String
  • + *
  • Integer
  • + *
  • Short
  • + *
  • Boolean
  • + *
  • Long
  • + *
  • Character
  • + *
  • Float
  • + *
  • Double
  • + *
  • Byte
  • + *
  • BigDecimal
  • + *
  • BigInteger
  • + *
  • Enum
  • + *
  • Number
  • + *
  • Date
  • + *
  • java.sql.Time
  • + *
  • java.sql.Timestamp
  • + *
  • java.sql.Timestamp
  • + *
  • LocalDateTime
  • + *
  • LocalDate
  • + *
  • LocalTime
  • + *
+ * 通过实现此接口,最简单方式为通过实现{@link #getObj(Object, Object)}方法,完成所有类型的值获取,获取默认采用 + * {@link Convert}方式自动转换。如果有自定义实现,重写对应getXXX方法即可。 + * + * @param 键类型 + * @author Looly + * @since 6.0.0 + */ +public interface TypeGetter { + /*-------------------------- 基本类型 start -------------------------------*/ + + /** + * 获取Object属性值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + Object getObj(K key, Object defaultValue); + + /** + * 获取Object属性值,最原始的对象获取,没有任何转换或类型判断 + * + * @param key 属性名 + * @return 属性值 + */ + default Object getObj(final K key) { + return getObj(key, null); + } + + /** + * 获取指定类型的值,默认自动转换值类型 + * + * @param 目标类型 + * @param key 键 + * @param type 目标类型 + * @return 结果值 + */ + default T get(final K key, final Type type) { + return get(key, type, null); + } + + /** + * 获取指定类型的值,默认自动转换值类型 + * + * @param 目标类型 + * @param key 键 + * @param type 目标类型 + * @param defaultValue 默认值 + * @return 结果值 + */ + default T get(final K key, final Type type, final T defaultValue) { + return Convert.convert(type, getObj(key), defaultValue); + } + + /** + * 获取字符串型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default String getStr(final K key, final String defaultValue) { + return get(key, String.class, defaultValue); + } + + /** + * 获取字符串型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default String getStr(final K key) { + return getStr(key, null); + } + + /** + * 获取int型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default Integer getInt(final K key, final Integer defaultValue) { + return get(key, Integer.class, defaultValue); + } + + /** + * 获取int型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default Integer getInt(final K key) { + return getInt(key, null); + } + + /** + * 获取short型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default Short getShort(final K key, final Short defaultValue) { + return get(key, Short.class, defaultValue); + } + + /** + * 获取short型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default Short getShort(final K key) { + return getShort(key, null); + } + + /** + * 获取boolean型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default Boolean getBool(final K key, final Boolean defaultValue) { + return get(key, Boolean.class, defaultValue); + } + + /** + * 获取boolean型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default Boolean getBool(final K key) { + return getBool(key, null); + } + + /** + * 获取Long型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default Long getLong(final K key, final Long defaultValue) { + return get(key, Long.class, defaultValue); + } + + /** + * 获取long型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default Long getLong(final K key) { + return getLong(key, null); + } + + /** + * 获取char型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default Character getChar(final K key, final Character defaultValue) { + return get(key, Character.class, defaultValue); + } + + /** + * 获取char型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default Character getChar(final K key) { + return getChar(key, null); + } + + /** + * 获取float型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default Float getFloat(final K key, final Float defaultValue) { + return get(key, Float.class, defaultValue); + } + + /** + * 获取float型属性值
+ * + * @param key 属性名 + * @return 属性值 + */ + default Float getFloat(final K key) { + return getFloat(key, null); + } + + /** + * 获取double型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default Double getDouble(final K key, final Double defaultValue) { + return get(key, Double.class, defaultValue); + } + + /** + * 获取double型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default Double getDouble(final K key) { + return getDouble(key, null); + } + + /** + * 获取byte型属性值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default Byte getByte(final K key, final Byte defaultValue) { + return get(key, Byte.class, defaultValue); + } + + /** + * 获取byte型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default Byte getByte(final K key) { + return getByte(key, null); + } + + /** + * 获取bytes型属性值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default byte[] getBytes(final K key, final byte[] defaultValue) { + return get(key, byte[].class, defaultValue); + } + + /** + * 获取bytes型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default byte[] getBytes(final K key) { + return getBytes(key, null); + } + + /** + * 获取BigDecimal型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default BigDecimal getBigDecimal(final K key, final BigDecimal defaultValue) { + return get(key, BigDecimal.class, defaultValue); + } + + /** + * 获取BigDecimal型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default BigDecimal getBigDecimal(final K key) { + return getBigDecimal(key, null); + } + + /** + * 获取BigInteger型属性值
+ * 若获得的值为不可见字符,使用默认值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return 属性值,无对应值返回defaultValue + */ + default BigInteger getBigInteger(final K key, final BigInteger defaultValue) { + return get(key, BigInteger.class, defaultValue); + } + + /** + * 获取BigInteger型属性值 + * + * @param key 属性名 + * @return 属性值 + */ + default BigInteger getBigInteger(final K key) { + return getBigInteger(key, null); + } + + /** + * 获得Enum类型的值 + * + * @param 枚举类型 + * @param clazz Enum的Class + * @param key KEY + * @param defaultValue 默认值 + * @return Enum类型的值,无则返回Null + */ + default > E getEnum(final Class clazz, final K key, final E defaultValue) { + return get(key, clazz, defaultValue); + } + + /** + * 获得Enum类型的值 + * + * @param 枚举类型 + * @param clazz Enum的Class + * @param key KEY + * @return Enum类型的值,无则返回Null + */ + default > E getEnum(final Class clazz, final K key) { + return getEnum(clazz, key, null); + } + + /** + * 获取Number类型值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return Number类型属性值 + */ + default Number getNumber(final K key, final Number defaultValue) { + return get(key, Number.class, defaultValue); + } + + /** + * 获取Number类型值 + * + * @param key 属性名 + * @return Number类型属性值 + */ + default Number getNumber(final K key) { + return getNumber(key, null); + } + + /** + * 获取Date类型值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return Date类型属性值 + */ + default Date getDate(final K key, final Date defaultValue) { + return get(key, Date.class, defaultValue); + } + + /** + * 获取Date类型值 + * + * @param key 属性名 + * @return Date类型属性值 + */ + default Date getDate(final K key) { + return getDate(key, null); + } + + /** + * 获取LocalTime类型值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return LocalTime类型属性值 + */ + default Time getSqlTime(final K key, final Time defaultValue) { + return get(key, Time.class, defaultValue); + } + + /** + * 获取Time类型值 + * + * @param key 属性名 + * @return Time类型属性值 + */ + default Time getSqlTime(final K key) { + return getSqlTime(key, null); + } + + /** + * 获取Timestamp类型值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return Timestamp类型属性值 + */ + default Timestamp getSqlTimestamp(final K key, final Timestamp defaultValue) { + return get(key, Timestamp.class, defaultValue); + } + + /** + * 获取Timestamp类型值 + * + * @param key 属性名 + * @return Timestamp类型属性值 + */ + default Timestamp getSqlTimestamp(final K key) { + return getSqlTimestamp(key, null); + } + + /** + * 获取LocalDateTime类型值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return LocalDateTime类型属性值 + */ + default LocalDateTime getLocalDateTime(final K key, final LocalDateTime defaultValue) { + return get(key, LocalDateTime.class, defaultValue); + } + + /** + * 获取LocalDateTime类型值 + * + * @param key 属性名 + * @return LocalDateTime类型属性值 + */ + default LocalDateTime getLocalDateTime(final K key) { + return getLocalDateTime(key, null); + } + + /** + * 获取LocalDate类型值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return LocalTime类型属性值 + */ + default LocalDate getLocalDate(final K key, final LocalDate defaultValue) { + return get(key, LocalDate.class, defaultValue); + } + + /** + * 获取LocalDate类型值 + * + * @param key 属性名 + * @return LocalTime类型属性值 + */ + default LocalDate getLocalDate(final K key) { + return getLocalDate(key, null); + } + + /** + * 获取LocalTime类型值 + * + * @param key 属性名 + * @param defaultValue 默认值 + * @return LocalTime类型属性值 + */ + default LocalTime getLocalTime(final K key, final LocalTime defaultValue) { + return get(key, LocalTime.class, defaultValue); + } + + /** + * 获取LocalTime类型值 + * + * @param key 属性名 + * @return LocalTime类型属性值 + */ + default LocalTime getLocalTime(final K key) { + return getLocalTime(key, null); + } + /*-------------------------- 基本类型 end -------------------------------*/ +} diff --git a/hutool-core/src/main/java/cn/hutool/core/map/Dict.java b/hutool-core/src/main/java/cn/hutool/core/map/Dict.java index 0e952b505..f75b6aa62 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/Dict.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/Dict.java @@ -9,15 +9,10 @@ import cn.hutool.core.exceptions.CloneRuntimeException; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.func.LambdaUtil; import cn.hutool.core.lang.func.SerSupplier; -import cn.hutool.core.lang.getter.BasicTypeGetter; +import cn.hutool.core.lang.getter.TypeGetter; import java.lang.reflect.Type; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.sql.Time; -import java.sql.Timestamp; import java.util.Arrays; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -29,7 +24,7 @@ import java.util.Objects; * * @author looly */ -public class Dict extends CustomKeyMap implements BasicTypeGetter { +public class Dict extends CustomKeyMap implements TypeGetter { private static final long serialVersionUID = 6135423866861206530L; static final float DEFAULT_LOAD_FACTOR = 0.75f; @@ -352,10 +347,9 @@ public class Dict extends CustomKeyMap implements BasicTypeGette // -------------------------------------------------------------------- Set end // -------------------------------------------------------------------- Get start - @Override - public Object getObj(final String key) { - return super.get(key); + public Object getObj(final String key, final Object defaultValue) { + return getOrDefault(key, defaultValue); } /** @@ -366,151 +360,9 @@ public class Dict extends CustomKeyMap implements BasicTypeGette * @return 字段值 * @since 4.6.3 */ - public T getBean(final String attr) { - return get(attr, null); - } - - /** - * 获得特定类型值 - * - * @param 值类型 - * @param attr 字段名 - * @param defaultValue 默认值 - * @return 字段值 - */ @SuppressWarnings("unchecked") - public T get(final String attr, final T defaultValue) { - final Object result = get(attr); - return (T) (result != null ? result : defaultValue); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - @Override - public String getStr(final String attr) { - return Convert.toStr(get(attr), null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - @Override - public Integer getInt(final String attr) { - return Convert.toInt(get(attr), null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - @Override - public Long getLong(final String attr) { - return Convert.toLong(get(attr), null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - @Override - public Float getFloat(final String attr) { - return Convert.toFloat(get(attr), null); - } - - @Override - public Short getShort(final String attr) { - return Convert.toShort(get(attr), null); - } - - @Override - public Character getChar(final String attr) { - return Convert.toChar(get(attr), null); - } - - @Override - public Double getDouble(final String attr) { - return Convert.toDouble(get(attr), null); - } - - @Override - public Byte getByte(final String attr) { - return Convert.toByte(get(attr), null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - @Override - public Boolean getBool(final String attr) { - return Convert.toBool(get(attr), null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - @Override - public BigDecimal getBigDecimal(final String attr) { - return Convert.toBigDecimal(get(attr)); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - @Override - public BigInteger getBigInteger(final String attr) { - return Convert.toBigInteger(get(attr)); - } - - @Override - public > E getEnum(final Class clazz, final String key) { - return Convert.toEnum(clazz, get(key)); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - public byte[] getBytes(final String attr) { - return get(attr, null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - @Override - public Date getDate(final String attr) { - return get(attr, null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - public Time getTime(final String attr) { - return get(attr, null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - public Timestamp getTimestamp(final String attr) { - return get(attr, null); - } - - /** - * @param attr 字段名 - * @return 字段值 - */ - public Number getNumber(final String attr) { - return get(attr, null); + public T getBean(final String attr) { + return (T) get(attr); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/map/MapProxy.java b/hutool-core/src/main/java/cn/hutool/core/map/MapProxy.java index dc16f4a9c..8bf8cbb51 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/MapProxy.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapProxy.java @@ -1,11 +1,11 @@ package cn.hutool.core.map; +import cn.hutool.core.classloader.ClassLoaderUtil; import cn.hutool.core.convert.Convert; -import cn.hutool.core.lang.getter.OptNullBasicTypeFromObjectGetter; +import cn.hutool.core.lang.getter.TypeGetter; +import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.BooleanUtil; -import cn.hutool.core.classloader.ClassLoaderUtil; -import cn.hutool.core.text.StrUtil; import java.io.Serializable; import java.lang.reflect.InvocationHandler; @@ -21,7 +21,7 @@ import java.util.Set; * @author looly * @since 3.2.0 */ -public class MapProxy implements Map, OptNullBasicTypeFromObjectGetter, InvocationHandler, Serializable { +public class MapProxy implements Map, TypeGetter, InvocationHandler, Serializable { private static final long serialVersionUID = 1L; @SuppressWarnings("rawtypes") @@ -32,7 +32,7 @@ public class MapProxy implements Map, OptNullBasicTypeFromObject * 此类对Map做一次包装,提供各种getXXX方法 * * @param map 被代理的Map - * @return {@link MapProxy} + * @return {@code MapProxy} */ public static MapProxy of(final Map map) { return (map instanceof MapProxy) ? (MapProxy) map : new MapProxy(map); @@ -47,10 +47,10 @@ public class MapProxy implements Map, OptNullBasicTypeFromObject this.map = map; } + @SuppressWarnings("unchecked") @Override public Object getObj(final Object key, final Object defaultValue) { - final Object value = map.get(key); - return null != value ? value : defaultValue; + return map.getOrDefault(key, defaultValue); } @Override diff --git a/hutool-core/src/main/java/cn/hutool/core/map/multi/ListValueMap.java b/hutool-core/src/main/java/cn/hutool/core/map/multi/ListValueMap.java index 90f79cc01..af5c96f86 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/multi/ListValueMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/multi/ListValueMap.java @@ -22,7 +22,7 @@ public class ListValueMap extends AbsCollValueMap { * * @param mapFactory 创建集合的工厂反方 */ - public ListValueMap(Supplier>> mapFactory) { + public ListValueMap(final Supplier>> mapFactory) { super(mapFactory); } @@ -31,7 +31,7 @@ public class ListValueMap extends AbsCollValueMap { * * @param map 提供数据的原始集合 */ - public ListValueMap(Map> map) { + public ListValueMap(final Map> map) { super(map); } diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java index 373adc478..cc7e2ccec 100755 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java @@ -3420,7 +3420,6 @@ public class CharSequenceUtil extends StrChecker { /** * 替换所有正则匹配的文本,并使用自定义函数决定如何替换
* replaceFun可以提取出匹配到的内容的不同部分,然后经过重新处理、组装变成新的内容放回原位。 - * *
 	 *     replace(this.content, "(\\d+)", parameters -> "-" + parameters.group(1) + "-")
 	 *     // 结果为:"ZZZaaabbbccc中文-1234-"
diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/MapProxyTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/MapProxyTest.java
index fbef8399f..d799d1cd7 100644
--- a/hutool-core/src/test/java/cn/hutool/core/collection/MapProxyTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/collection/MapProxyTest.java
@@ -1,15 +1,14 @@
 package cn.hutool.core.collection;
 
+import cn.hutool.core.map.MapProxy;
+import org.junit.Assert;
+import org.junit.Test;
+
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-import org.junit.Assert;
-import org.junit.Test;
-
-import cn.hutool.core.map.MapProxy;
-
 public class MapProxyTest {
 
 	@Test
@@ -26,6 +25,7 @@ public class MapProxyTest {
 		Assert.assertFalse(keys.isEmpty());
 
 		final Set> entrys = mapProxy.entrySet();
+		//noinspection ConstantConditions
 		Assert.assertFalse(entrys.isEmpty());
 	}
 
diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java
index b7488efc2..52d75769b 100755
--- a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java
@@ -360,6 +360,8 @@ public class ConvertTest {
 		final String str = "33020000210909112800000124";
 		final BigDecimal bigDecimal = Convert.toBigDecimal(str);
 		Assert.assertEquals(str, bigDecimal.toPlainString());
+
+		Assert.assertNull(Convert.toBigDecimal("  "));
 	}
 
 	@Test
diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java
index be03d08bd..73169ef77 100644
--- a/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java
@@ -62,11 +62,15 @@ public class AbstractEnhancedWrappedStreamTest {
 	public void testToMap() {
 		final List list = asList(1, 2, 3);
 		final Map identityMap = wrap(list).toMap(String::valueOf);
-		Assert.assertEquals(new HashMap() {{
-			put("1", 1);
-			put("2", 2);
-			put("3", 3);
-		}}, identityMap);
+		Assert.assertEquals(new HashMap() {
+			private static final long serialVersionUID = 1L;
+
+			{
+				put("1", 1);
+				put("2", 2);
+				put("3", 3);
+			}
+		}, identityMap);
 	}
 
 	@Test
@@ -82,11 +86,15 @@ public class AbstractEnhancedWrappedStreamTest {
 		final List orders = asList(1, 2, 3);
 		final List list = asList("dromara", "hutool", "sweet");
 		final Map toZip = wrap(orders).toZip(list);
-		Assert.assertEquals(new HashMap() {{
-			put(1, "dromara");
-			put(2, "hutool");
-			put(3, "sweet");
-		}}, toZip);
+		Assert.assertEquals(new HashMap() {
+			private static final long serialVersionUID = 1L;
+
+			{
+				put(1, "dromara");
+				put(2, "hutool");
+				put(3, "sweet");
+			}
+		}, toZip);
 	}
 
 	@Test
@@ -150,11 +158,15 @@ public class AbstractEnhancedWrappedStreamTest {
 	@Test
 	public void testGrouping() {
 		final List list = asList(1, 2, 3);
-		final Map> map = new HashMap>() {{
-			put("1", singletonList(1));
-			put("2", singletonList(2));
-			put("3", singletonList(3));
-		}};
+		final Map> map = new HashMap>() {
+			private static final long serialVersionUID = 1L;
+
+			{
+				put("1", singletonList(1));
+				put("2", singletonList(2));
+				put("3", singletonList(3));
+			}
+		};
 
 		Map> group = wrap(list).group(String::valueOf, HashMap::new, Collectors.toList());
 		Assert.assertEquals(map, group);
@@ -167,10 +179,13 @@ public class AbstractEnhancedWrappedStreamTest {
 	@Test
 	public void testPartitioning() {
 		final List list = asList(1, 2, 3);
-		final Map> map = new HashMap>() {{
-			put(Boolean.TRUE, singletonList(2));
-			put(Boolean.FALSE, asList(1, 3));
-		}};
+		final Map> map = new HashMap>() {
+			private static final long serialVersionUID = 1L;
+			{
+				put(Boolean.TRUE, singletonList(2));
+				put(Boolean.FALSE, asList(1, 3));
+			}
+		};
 
 		Map> partition = wrap(list).partition(t -> (t & 1) == 0, Collectors.toList());
 		Assert.assertEquals(map, partition);
@@ -553,7 +568,7 @@ public class AbstractEnhancedWrappedStreamTest {
 
 	@Test
 	public void testFlatTree() {
-		final Tree root = new Tree(1, asList(new Tree(2, asList(new Tree(3, Collections.emptyList())))));
+		final Tree root = new Tree(1, ListUtil.of(new Tree(2, ListUtil.of(new Tree(3, Collections.emptyList())))));
 		Assert.assertEquals(3L, wrap(root).flatTree(Tree::getChildren, Tree::setChildren).count());
 	}
 
@@ -567,7 +582,7 @@ public class AbstractEnhancedWrappedStreamTest {
 	@Test
 	public void testMapNonNull() {
 		Assert.assertEquals(
-				asList("3"), wrap(null, 2, 3, 4).mapNonNull(t -> ((t & 1) == 0) ? null : String.valueOf(t)).toList()
+				ListUtil.of("3"), wrap(null, 2, 3, 4).mapNonNull(t -> ((t & 1) == 0) ? null : String.valueOf(t)).toList()
 		);
 	}
 
@@ -636,7 +651,7 @@ public class AbstractEnhancedWrappedStreamTest {
 		List zip = wrap(orders).zip(list, (e1, e2) -> e1 + "." + e2).toList();
 		Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip);
 
-		zip = this.wrap((Stream)EasyStream.iterate(1, i -> i + 1)).limit(10).zip(list, (e1, e2) -> e1 + "." + e2).toList();
+		zip = this.wrap((Stream) EasyStream.iterate(1, i -> i + 1)).limit(10).zip(list, (e1, e2) -> e1 + "." + e2).toList();
 		Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip);
 	}
 
diff --git a/hutool-db/src/main/java/cn/hutool/db/Entity.java b/hutool-db/src/main/java/cn/hutool/db/Entity.java
index 176eb3eea..f9cdb7a54 100755
--- a/hutool-db/src/main/java/cn/hutool/db/Entity.java
+++ b/hutool-db/src/main/java/cn/hutool/db/Entity.java
@@ -8,6 +8,7 @@ import cn.hutool.core.reflect.MethodUtil;
 import cn.hutool.core.text.StrUtil;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.db.sql.SqlUtil;
 
 import java.nio.charset.Charset;
@@ -273,28 +274,28 @@ public class Entity extends Dict {
 	// -------------------------------------------------------------------- Get start
 
 	/**
-	 * 获得Clob类型结果
+	 * 获得Clob类型结果,如果结果类型非Clob,不做转换,直接抛出异常
 	 *
 	 * @param field 参数
 	 * @return Clob
 	 */
 	public Clob getClob(final String field) {
-		return get(field, null);
+		return (Clob) get(field);
 	}
 
 	/**
-	 * 获得Blob类型结果
+	 * 获得Blob类型结果,如果结果类型非Blob,不做转换,直接抛出异常
 	 *
 	 * @param field 参数
 	 * @return Blob
 	 * @since 3.0.6
 	 */
 	public Blob getBlob(final String field) {
-		return get(field, null);
+		return (Blob) get(field);
 	}
 
 	@Override
-	public Time getTime(final String field) {
+	public Time getSqlTime(final String field, final Time defaultValue) {
 		final Object obj = get(field);
 		Time result = null;
 		if (null != obj) {
@@ -305,11 +306,11 @@ public class Entity extends Dict {
 				result = MethodUtil.invoke(obj, "timeValue");
 			}
 		}
-		return result;
+		return ObjUtil.defaultIfNull(result, defaultValue);
 	}
 
 	@Override
-	public Date getDate(final String field) {
+	public Date getDate(final String field, final Date defaultValue) {
 		final Object obj = get(field);
 		Date result = null;
 		if (null != obj) {
@@ -320,11 +321,11 @@ public class Entity extends Dict {
 				result = MethodUtil.invoke(obj, "dateValue");
 			}
 		}
-		return result;
+		return ObjUtil.defaultIfNull(result, defaultValue);
 	}
 
 	@Override
-	public Timestamp getTimestamp(final String field) {
+	public Timestamp getSqlTimestamp(final String field, final Timestamp defaultValue) {
 		final Object obj = get(field);
 		Timestamp result = null;
 		if (null != obj) {
@@ -335,12 +336,12 @@ public class Entity extends Dict {
 				result = MethodUtil.invoke(obj, "timestampValue");
 			}
 		}
-		return result;
+		return ObjUtil.defaultIfNull(result, defaultValue);
 	}
 
 	@Override
-	public String getStr(final String field) {
-		return getStr(field, CharsetUtil.UTF_8);
+	public String getStr(final String field, final String defaultValue) {
+		return getStr(field, CharsetUtil.UTF_8, defaultValue);
 	}
 
 	/**
@@ -350,10 +351,9 @@ public class Entity extends Dict {
 	 * @param field   字段名
 	 * @param charset 编码
 	 * @return 字段对应值
-	 * @since 3.0.6
 	 */
-	public String getStr(final String field, final Charset charset) {
-		final Object obj = get(field);
+	public String getStr(final String field, final Charset charset, final String defaultValue) {
+		final Object obj = getObj(field, defaultValue);
 		if (obj instanceof Clob) {
 			return SqlUtil.clobToStr((Clob) obj);
 		} else if (obj instanceof Blob) {
@@ -362,7 +362,7 @@ public class Entity extends Dict {
 			final RowId rowId = (RowId) obj;
 			return StrUtil.str(rowId.getBytes(), charset);
 		}
-		return super.getStr(field);
+		return super.getStr(field, defaultValue);
 	}
 
 	/**
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/AbstractDSFactory.java b/hutool-db/src/main/java/cn/hutool/db/ds/AbstractDSFactory.java
index 7dd3d5569..5ac0c7d96 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/AbstractDSFactory.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/AbstractDSFactory.java
@@ -102,7 +102,7 @@ public abstract class AbstractDSFactory extends DSFactory {
 		}
 
 		// 基本信息
-		final String url = config.getAndRemoveStr(KEY_ALIAS_URL);
+		final String url = config.getAndRemove(KEY_ALIAS_URL);
 		if (StrUtil.isBlank(url)) {
 			throw new DbRuntimeException("No JDBC URL for group: [{}]", group);
 		}
@@ -112,12 +112,12 @@ public abstract class AbstractDSFactory extends DSFactory {
 		DbUtil.removeShowSqlParams(config);
 
 		// 自动识别Driver
-		String driver = config.getAndRemoveStr(KEY_ALIAS_DRIVER);
+		String driver = config.getAndRemove(KEY_ALIAS_DRIVER);
 		if (StrUtil.isBlank(driver)) {
 			driver = DriverUtil.identifyDriver(url);
 		}
-		final String user = config.getAndRemoveStr(KEY_ALIAS_USER);
-		final String pass = config.getAndRemoveStr(KEY_ALIAS_PASSWORD);
+		final String user = config.getAndRemove(KEY_ALIAS_USER);
+		final String pass = config.getAndRemove(KEY_ALIAS_PASSWORD);
 
 		return DataSourceWrapper.wrap(createDataSource(url, driver, user, pass, config), driver);
 	}
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/bee/BeeDSFactory.java b/hutool-db/src/main/java/cn/hutool/db/ds/bee/BeeDSFactory.java
index b156739d0..33511dd8b 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/bee/BeeDSFactory.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/bee/BeeDSFactory.java
@@ -36,7 +36,7 @@ public class BeeDSFactory extends AbstractDSFactory {
 		// remarks等特殊配置,since 5.3.8
 		String connValue;
 		for (final String key : KEY_CONN_PROPS) {
-			connValue = poolSetting.getAndRemoveStr(key);
+			connValue = poolSetting.getAndRemove(key);
 			if(StrUtil.isNotBlank(connValue)){
 				beeConfig.addConnectProperty(key, connValue);
 			}
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/c3p0/C3p0DSFactory.java b/hutool-db/src/main/java/cn/hutool/db/ds/c3p0/C3p0DSFactory.java
index 175aee9d6..148c56e63 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/c3p0/C3p0DSFactory.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/c3p0/C3p0DSFactory.java
@@ -46,7 +46,7 @@ public class C3p0DSFactory extends AbstractDSFactory {
 		final Props connProps = new Props();
 		String connValue;
 		for (final String key : KEY_CONN_PROPS) {
-			connValue = poolSetting.getAndRemoveStr(key);
+			connValue = poolSetting.getAndRemove(key);
 			if(StrUtil.isNotBlank(connValue)){
 				connProps.setProperty(key, connValue);
 			}
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/dbcp/DbcpDSFactory.java b/hutool-db/src/main/java/cn/hutool/db/ds/dbcp/DbcpDSFactory.java
index 8f190418b..a6aa80fa2 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/dbcp/DbcpDSFactory.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/dbcp/DbcpDSFactory.java
@@ -38,7 +38,7 @@ public class DbcpDSFactory extends AbstractDSFactory {
 		// remarks等特殊配置,since 5.3.8
 		String connValue;
 		for (final String key : KEY_CONN_PROPS) {
-			connValue = poolSetting.getAndRemoveStr(key);
+			connValue = poolSetting.getAndRemove(key);
 			if(StrUtil.isNotBlank(connValue)){
 				ds.addConnectionProperty(key, connValue);
 			}
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/druid/DruidDSFactory.java b/hutool-db/src/main/java/cn/hutool/db/ds/druid/DruidDSFactory.java
index 71a6dca67..97ba452a0 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/druid/DruidDSFactory.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/druid/DruidDSFactory.java
@@ -49,7 +49,7 @@ public class DruidDSFactory extends AbstractDSFactory {
 		// Druid中也可以通过 druid.connectProperties 属性设置
 		String connValue;
 		for (final String key : KEY_CONN_PROPS) {
-			connValue = poolSetting.getAndRemoveStr(key);
+			connValue = poolSetting.getAndRemove(key);
 			if(StrUtil.isNotBlank(connValue)){
 				ds.addConnectionProperty(key, connValue);
 			}
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/hikari/HikariDSFactory.java b/hutool-db/src/main/java/cn/hutool/db/ds/hikari/HikariDSFactory.java
index 0b0ecfbe6..dbb57fb3d 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/hikari/HikariDSFactory.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/hikari/HikariDSFactory.java
@@ -34,7 +34,7 @@ public class HikariDSFactory extends AbstractDSFactory {
 		final Props connProps = new Props();
 		String connValue;
 		for (final String key : KEY_CONN_PROPS) {
-			connValue = poolSetting.getAndRemoveStr(key);
+			connValue = poolSetting.getAndRemove(key);
 			if(StrUtil.isNotBlank(connValue)){
 				connProps.setProperty(key, connValue);
 			}
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/pooled/DbSetting.java b/hutool-db/src/main/java/cn/hutool/db/ds/pooled/DbSetting.java
index f12745109..60a899d9b 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/pooled/DbSetting.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/pooled/DbSetting.java
@@ -54,22 +54,22 @@ public class DbSetting {
 		final DbConfig dbConfig = new DbConfig();
 
 		// 基本信息
-		final String url = config.getAndRemoveStr(DSFactory.KEY_ALIAS_URL);
+		final String url = config.getAndRemove(DSFactory.KEY_ALIAS_URL);
 		if (StrUtil.isBlank(url)) {
 			throw new DbRuntimeException("No JDBC URL for group: [{}]", group);
 		}
 		dbConfig.setUrl(url);
 		// 自动识别Driver
-		final String driver = config.getAndRemoveStr(DSFactory.KEY_ALIAS_DRIVER);
+		final String driver = config.getAndRemove(DSFactory.KEY_ALIAS_DRIVER);
 		dbConfig.setDriver(StrUtil.isNotBlank(driver) ? driver : DriverUtil.identifyDriver(url));
-		dbConfig.setUser(config.getAndRemoveStr(DSFactory.KEY_ALIAS_USER));
-		dbConfig.setPass(config.getAndRemoveStr(DSFactory.KEY_ALIAS_PASSWORD));
+		dbConfig.setUser(config.getAndRemove(DSFactory.KEY_ALIAS_USER));
+		dbConfig.setPass(config.getAndRemove(DSFactory.KEY_ALIAS_PASSWORD));
 
 		// 连接池相关信息
-		dbConfig.setInitialSize(setting.getInt("initialSize", group, 0));
-		dbConfig.setMinIdle(setting.getInt("minIdle", group, 0));
-		dbConfig.setMaxActive(setting.getInt("maxActive", group, 8));
-		dbConfig.setMaxWait(setting.getLong("maxWait", group, 6000L));
+		dbConfig.setInitialSize(setting.getIntByGroup("initialSize", group, 0));
+		dbConfig.setMinIdle(setting.getIntByGroup("minIdle", group, 0));
+		dbConfig.setMaxActive(setting.getIntByGroup("maxActive", group, 8));
+		dbConfig.setMaxWait(setting.getLongByGroup("maxWait", group, 6000L));
 
 		// remarks等特殊配置,since 5.3.8
 		String connValue;
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/simple/SimpleDataSource.java b/hutool-db/src/main/java/cn/hutool/db/ds/simple/SimpleDataSource.java
index 9b2aa3df9..6e21137f7 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/simple/SimpleDataSource.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/simple/SimpleDataSource.java
@@ -86,10 +86,10 @@ public class SimpleDataSource extends AbstractDataSource {
 		}
 
 		init(//
-				config.getAndRemoveStr(DSFactory.KEY_ALIAS_URL), //
-				config.getAndRemoveStr(DSFactory.KEY_ALIAS_USER), //
-				config.getAndRemoveStr(DSFactory.KEY_ALIAS_PASSWORD), //
-				config.getAndRemoveStr(DSFactory.KEY_ALIAS_DRIVER)//
+				config.getAndRemove(DSFactory.KEY_ALIAS_URL), //
+				config.getAndRemove(DSFactory.KEY_ALIAS_USER), //
+				config.getAndRemove(DSFactory.KEY_ALIAS_PASSWORD), //
+				config.getAndRemove(DSFactory.KEY_ALIAS_DRIVER)//
 		);
 
 		// 其它连接参数
diff --git a/hutool-db/src/main/java/cn/hutool/db/ds/tomcat/TomcatDSFactory.java b/hutool-db/src/main/java/cn/hutool/db/ds/tomcat/TomcatDSFactory.java
index 53535a84a..94975f446 100644
--- a/hutool-db/src/main/java/cn/hutool/db/ds/tomcat/TomcatDSFactory.java
+++ b/hutool-db/src/main/java/cn/hutool/db/ds/tomcat/TomcatDSFactory.java
@@ -46,7 +46,7 @@ public class TomcatDSFactory extends AbstractDSFactory {
 		final Props connProps = new Props();
 		String connValue;
 		for (final String key : KEY_CONN_PROPS) {
-			connValue = poolSetting.getAndRemoveStr(key);
+			connValue = poolSetting.getAndRemove(key);
 			if(StrUtil.isNotBlank(connValue)){
 				connProps.setProperty(key, connValue);
 			}
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java b/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java
index 8a01af8ab..063cd7d04 100755
--- a/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java
@@ -271,7 +271,7 @@ public class JSONConfig implements Serializable {
 	 * @return this
 	 * @since 5.8.5
 	 */
-	public JSONConfig setCheckDuplicate(boolean checkDuplicate) {
+	public JSONConfig setCheckDuplicate(final boolean checkDuplicate) {
 		this.checkDuplicate = checkDuplicate;
 		return this;
 	}
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java b/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java
index 15b586f21..0dab8cced 100644
--- a/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java
@@ -1,11 +1,9 @@
 package cn.hutool.json;
 
-import cn.hutool.core.convert.ConvertException;
-import cn.hutool.core.lang.getter.OptNullBasicTypeFromObjectGetter;
+import cn.hutool.core.lang.getter.TypeGetter;
 import cn.hutool.core.util.ObjUtil;
 
-import java.time.LocalDateTime;
-import java.util.Date;
+import java.lang.reflect.Type;
 import java.util.List;
 
 /**
@@ -14,7 +12,7 @@ import java.util.List;
  * @param  Key类型
  * @author Looly
  */
-public interface JSONGetter extends OptNullBasicTypeFromObjectGetter {
+public interface JSONGetter extends TypeGetter {
 
 	/**
 	 * 获取JSON配置
@@ -126,49 +124,12 @@ public interface JSONGetter extends OptNullBasicTypeFromObjectGetter {
 	}
 
 	@Override
-	default Date getDate(final K key, final Date defaultValue) {
-		return get(key, Date.class);
-	}
-
-	/**
-	 * 获取{@link LocalDateTime}类型值
-	 *
-	 * @param key          键
-	 * @param defaultValue 默认值
-	 * @return {@link LocalDateTime}
-	 * @since 5.7.7
-	 */
-	default LocalDateTime getLocalDateTime(final K key, final LocalDateTime defaultValue) {
-		return ObjUtil.defaultIfNull(get(key, LocalDateTime.class), defaultValue);
-	}
-
-	/**
-	 * 获取byte[]数据
-	 *
-	 * @param key 键
-	 * @return 值
-	 */
-	default byte[] getBytes(final K key) {
-		return get(key, byte[].class);
-	}
-
-	/**
-	 * 获取指定类型的对象
-	 *
-	 * @param          获取的对象类型
-	 * @param key         键
-	 * @param type        获取对象类型
-	 * @return 对象
-	 * @throws ConvertException 转换异常
-	 * @since 3.0.8
-	 */
-	@SuppressWarnings("unchecked")
-	default  T get(final K key, final Class type) throws ConvertException {
+	default  T get(final K key, final Type type, final T defaultValue) {
 		final Object value = this.getObj(key);
 		if (ObjUtil.isNull(value)) {
-			return null;
+			return defaultValue;
 		}
 
-		return (T) getConfig().getConverter().convert(type, value);
+		return (T) getConfig().getConverter().convert(type, value, defaultValue);
 	}
 }
diff --git a/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java b/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java
index 617aa2119..1b35526a5 100644
--- a/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java
+++ b/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java
@@ -3,13 +3,11 @@ package cn.hutool.setting;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.bean.copier.CopyOptions;
 import cn.hutool.core.bean.copier.ValueProvider;
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.lang.getter.OptNullBasicTypeFromStringGetter;
+import cn.hutool.core.lang.getter.GroupedTypeGetter;
+import cn.hutool.core.lang.getter.TypeGetter;
 import cn.hutool.core.reflect.ConstructorUtil;
 import cn.hutool.core.text.StrUtil;
 import cn.hutool.core.util.ObjUtil;
-import cn.hutool.log.Log;
-import cn.hutool.log.LogFactory;
 
 import java.io.Serializable;
 import java.lang.reflect.Type;
@@ -19,35 +17,22 @@ import java.lang.reflect.Type;
  *
  * @author Looly
  */
-public abstract class AbsSetting implements OptNullBasicTypeFromStringGetter, Serializable {
+public abstract class AbsSetting implements TypeGetter,
+		GroupedTypeGetter, Serializable {
 	private static final long serialVersionUID = 6200156302595905863L;
-	private final static Log log = LogFactory.get();
 
 	/**
 	 * 数组类型值默认分隔符
 	 */
-	public final static String DEFAULT_DELIMITER = ",";
+	public final static String DEFAULT_DELIMITER = StrUtil.COMMA;
 	/**
 	 * 默认分组
 	 */
 	public final static String DEFAULT_GROUP = StrUtil.EMPTY;
 
 	@Override
-	public String getStr(final String key, final String defaultValue) {
-		return getStr(key, DEFAULT_GROUP, defaultValue);
-	}
-
-	/**
-	 * 获得字符串类型值
-	 *
-	 * @param key          KEY
-	 * @param group        分组
-	 * @param defaultValue 默认值
-	 * @return 值,如果字符串为{@code null}返回默认值
-	 */
-	public String getStr(final String key, final String group, final String defaultValue) {
-		final String value = getByGroup(key, group);
-		return ObjUtil.defaultIfNull(value, defaultValue);
+	public Object getObj(final CharSequence key, final Object defaultValue) {
+		return ObjUtil.defaultIfNull(getObjByGroup(key, DEFAULT_GROUP), defaultValue);
 	}
 
 	/**
@@ -57,53 +42,11 @@ public abstract class AbsSetting implements OptNullBasicTypeFromStringGetter
+	 * 若配置文件中键值对类似于:
+	 * 
+	 *     a = 1,2,3,4
+	 * 
+ * 则获取结果为:[1, 2, 3, 4] * * @param key 属性名 * @param group 分组名 * @return 属性值 */ - public String[] getStrings(final String key, final String group) { - return getStrings(key, group, DEFAULT_DELIMITER); + public String[] getStrsByGroup(final CharSequence key, final CharSequence group) { + return getStrsByGroup(key, group, DEFAULT_DELIMITER); } /** - * 获得数组型 + * 获得数组型,可自定义分隔符
+ * 假定分隔符为逗号,若配置文件中键值对类似于: + *
+	 *     a = 1,2,3,4
+	 * 
+ * 则获取结果为:[1, 2, 3, 4] * * @param key 属性名 * @param group 分组名 * @param delimiter 分隔符 * @return 属性值 */ - public String[] getStrings(final String key, final String group, final String delimiter) { - final String value = getByGroup(key, group); + public String[] getStrsByGroup(final CharSequence key, final CharSequence group, final CharSequence delimiter) { + final String value = getStrByGroup(key, group); if (StrUtil.isBlank(value)) { return null; } return StrUtil.splitToArray(value, delimiter); } - // --------------------------------------------------------------- Get int - - /** - * 获取数字型型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @return 属性值 - */ - public Integer getInt(final String key, final String group) { - return getInt(key, group, null); - } - - /** - * 获取数字型型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @param defaultValue 默认值 - * @return 属性值 - */ - public Integer getInt(final String key, final String group, final Integer defaultValue) { - return Convert.toInt(getByGroup(key, group), defaultValue); - } - - // --------------------------------------------------------------- Get bool - - /** - * 获取布尔型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @return 属性值 - */ - public Boolean getBool(final String key, final String group) { - return getBool(key, group, null); - } - - /** - * 获取布尔型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @param defaultValue 默认值 - * @return 属性值 - */ - public Boolean getBool(final String key, final String group, final Boolean defaultValue) { - return Convert.toBool(getByGroup(key, group), defaultValue); - } - - // --------------------------------------------------------------- Get long - - /** - * 获取long类型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @return 属性值 - */ - public Long getLong(final String key, final String group) { - return getLong(key, group, null); - } - - /** - * 获取long类型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @param defaultValue 默认值 - * @return 属性值 - */ - public Long getLong(final String key, final String group, final Long defaultValue) { - return Convert.toLong(getByGroup(key, group), defaultValue); - } - - // --------------------------------------------------------------- Get char - - /** - * 获取char类型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @return 属性值 - */ - public Character getChar(final String key, final String group) { - final String value = getByGroup(key, group); - if (StrUtil.isBlank(value)) { - return null; - } - return value.charAt(0); - } - - // --------------------------------------------------------------- Get double - - /** - * 获取double类型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @return 属性值 - */ - public Double getDouble(final String key, final String group) { - return getDouble(key, group, null); - } - - /** - * 获取double类型属性值 - * - * @param key 属性名 - * @param group 分组名 - * @param defaultValue 默认值 - * @return 属性值 - */ - public Double getDouble(final String key, final String group, final Double defaultValue) { - return Convert.toDouble(getByGroup(key, group), defaultValue); - } - /** * 将setting中的键值关系映射到对象中,原理是调用对象对应的set方法
* 只支持基本类型的转换 @@ -285,17 +121,17 @@ public abstract class AbsSetting implements OptNullBasicTypeFromStringGetter T toBean(final String group, final T bean) { + public T toBean(final CharSequence group, final T bean) { return BeanUtil.fillBean(bean, new ValueProvider() { @Override public Object value(final String key, final Type valueType) { - return getByGroup(key, group); + return getObjByGroup(key, group); } @Override public boolean containsKey(final String key) { - return null != getByGroup(key, group); + return null != getObjByGroup(key, group); } }, CopyOptions.of()); } @@ -310,7 +146,7 @@ public abstract class AbsSetting implements OptNullBasicTypeFromStringGetter T toBean(final String group, final Class beanClass) { + public T toBean(final CharSequence group, final Class beanClass) { return toBean(group, ConstructorUtil.newInstanceIfPossible(beanClass)); } diff --git a/hutool-setting/src/main/java/cn/hutool/setting/GroupedMap.java b/hutool-setting/src/main/java/cn/hutool/setting/GroupedMap.java index 51da1f6fc..7f75585e8 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/GroupedMap.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/GroupedMap.java @@ -35,12 +35,12 @@ public class GroupedMap extends LinkedHashMap map = this.get(StrUtil.emptyIfNull(group)); if (MapUtil.isNotEmpty(map)) { - return map.get(key); + return map.get(StrUtil.str(key)); } } finally { readLock.unlock(); diff --git a/hutool-setting/src/main/java/cn/hutool/setting/Setting.java b/hutool-setting/src/main/java/cn/hutool/setting/Setting.java index cbdf31652..d87f4e3ba 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/Setting.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/Setting.java @@ -4,11 +4,8 @@ import cn.hutool.core.collection.ListUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.io.resource.ClassPathResource; -import cn.hutool.core.io.resource.FileResource; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.io.resource.UrlResource; import cn.hutool.core.io.watch.SimpleWatcher; import cn.hutool.core.io.watch.WatchMonitor; import cn.hutool.core.io.watch.WatchUtil; @@ -85,6 +82,11 @@ public class Setting extends AbsSetting implements Map { */ protected Resource resource; + /** + * 当获取key对应值为{@code null}时是否打印debug日志提示用户,默认{@code false} + */ + private boolean logIfNull; + private SettingLoader settingLoader; private WatchMonitor watchMonitor; @@ -137,32 +139,7 @@ public class Setting extends AbsSetting implements Map { */ public Setting(final File configFile, final Charset charset, final boolean isUseVariable) { Assert.notNull(configFile, "Null setting file define!"); - this.init(new FileResource(configFile), charset, isUseVariable); - } - - /** - * 构造,相对于classes读取文件 - * - * @param path 相对ClassPath路径或绝对路径 - * @param clazz 基准类 - * @param charset 字符集 - * @param isUseVariable 是否使用变量 - */ - public Setting(final String path, final Class clazz, final Charset charset, final boolean isUseVariable) { - Assert.notBlank(path, "Blank setting path !"); - this.init(new ClassPathResource(path, clazz), charset, isUseVariable); - } - - /** - * 构造 - * - * @param url 设定文件的URL - * @param charset 字符集 - * @param isUseVariable 是否使用变量 - */ - public Setting(final URL url, final Charset charset, final boolean isUseVariable) { - Assert.notNull(url, "Null setting url define!"); - this.init(new UrlResource(url), charset, isUseVariable); + this.init(ResourceUtil.getResource(configFile), charset, isUseVariable); } /** @@ -278,26 +255,12 @@ public class Setting extends AbsSetting implements Map { } @Override - public String getByGroup(final String key, final String group) { - return this.groupedMap.get(group, key); - } - - /** - * 获取并删除键值对,当指定键对应值非空时,返回并删除这个值,后边的键对应的值不再查找 - * - * @param keys 键列表,常用于别名 - * @return 值 - * @since 3.1.2 - */ - public Object getAndRemove(final String... keys) { - Object value = null; - for (final String key : keys) { - value = remove(key); - if (null != value) { - break; - } + public Object getObjByGroup(final CharSequence key, final CharSequence group, final Object defaultValue) { + final String result = this.groupedMap.get(group, key); + if (result == null && logIfNull) { + StaticLog.debug("No key [{}] in group [{}] !", key, group); } - return value; + return result; } /** @@ -307,7 +270,7 @@ public class Setting extends AbsSetting implements Map { * @return 字符串值 * @since 3.1.2 */ - public String getAndRemoveStr(final String... keys) { + public String getAndRemove(final String... keys) { String value = null; for (final String key : keys) { value = remove(key); @@ -467,6 +430,16 @@ public class Setting extends AbsSetting implements Map { return this; } + /** + * 设置当获取key对应值为{@code null}时是否打印debug日志提示用户 + * @param logIfNull 当获取key对应值为{@code null}时是否打印debug日志提示用户 + * @return this + */ + public Setting setLogIfNull(final boolean logIfNull){ + this.logIfNull = logIfNull; + return this; + } + // ------------------------------------------------- Map interface with group /** @@ -501,17 +474,6 @@ public class Setting extends AbsSetting implements Map { return this.groupedMap.containsValue(group, value); } - /** - * 获取分组对应的值,如果分组不存在或者值不存在则返回null - * - * @param group 分组 - * @param key 键 - * @return 值,如果分组不存在或者值不存在则返回null - */ - public String get(final String group, final String key) { - return this.groupedMap.get(group, key); - } - /** * 将键值对加入到对应分组中 * @@ -666,7 +628,7 @@ public class Setting extends AbsSetting implements Map { */ @Override public String get(final Object key) { - return this.groupedMap.get(DEFAULT_GROUP, Convert.toStr(key)); + return getStr((String)key); } /** @@ -689,7 +651,7 @@ public class Setting extends AbsSetting implements Map { */ @Override public String remove(final Object key) { - return this.groupedMap.remove(DEFAULT_GROUP, Convert.toStr(key)); + return remove(DEFAULT_GROUP, key); } /** diff --git a/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java b/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java index e198d5d4a..6d2e24cc7 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java @@ -1,12 +1,9 @@ package cn.hutool.setting.dialect; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.convert.Convert; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.io.resource.ClassPathResource; -import cn.hutool.core.io.resource.FileResource; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.io.resource.UrlResource; @@ -14,26 +11,22 @@ import cn.hutool.core.io.watch.SimpleWatcher; import cn.hutool.core.io.watch.WatchMonitor; import cn.hutool.core.io.watch.WatchUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.lang.getter.BasicTypeGetter; -import cn.hutool.core.lang.getter.OptBasicTypeGetter; +import cn.hutool.core.lang.getter.TypeGetter; import cn.hutool.core.map.MapUtil; import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.ObjUtil; import cn.hutool.log.StaticLog; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.Writer; -import java.math.BigDecimal; -import java.math.BigInteger; import java.net.URL; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.WatchEvent; -import java.util.Date; import java.util.Properties; /** @@ -41,7 +34,7 @@ import java.util.Properties; * * @author loolly */ -public final class Props extends Properties implements BasicTypeGetter, OptBasicTypeGetter { +public final class Props extends Properties implements TypeGetter { private static final long serialVersionUID = 1935981579709590740L; /** @@ -78,29 +71,18 @@ public final class Props extends Properties implements BasicTypeGetter, * @param resource 资源(相对Classpath的路径) * @return Props */ - public static Props getProp(final String resource) { + public static Props of(final String resource) { return new Props(resource); } - /** - * 获得Classpath下的Properties文件 - * - * @param resource 资源(相对Classpath的路径) - * @param charsetName 字符集 - * @return Properties - */ - public static Props getProp(final String resource, final String charsetName) { - return new Props(resource, charsetName); - } - /** * 获得Classpath下的Properties文件 * * @param resource 资源(相对Classpath的路径) - * @param charset 字符集 + * @param charset 自定义编码 * @return Properties */ - public static Props getProp(final String resource, final Charset charset) { + public static Props of(final String resource, final Charset charset) { return new Props(resource, charset); } @@ -118,24 +100,14 @@ public final class Props extends Properties implements BasicTypeGetter, * @param path 配置文件路径,相对于ClassPath,或者使用绝对路径 */ public Props(final String path) { - this(path, CharsetUtil.ISO_8859_1); - } - - /** - * 构造,使用相对于Class文件根目录的相对路径 - * - * @param path 相对或绝对路径 - * @param charsetName 字符集 - */ - public Props(final String path, final String charsetName) { - this(path, CharsetUtil.charset(charsetName)); + this(path, null); } /** * 构造,使用相对于Class文件根目录的相对路径 * * @param path 相对或绝对路径 - * @param charset 字符集 + * @param charset 自定义编码 */ public Props(final String path, final Charset charset) { Assert.notBlank(path, "Blank properties file path !"); @@ -151,98 +123,35 @@ public final class Props extends Properties implements BasicTypeGetter, * @param propertiesFile 配置文件对象 */ public Props(final File propertiesFile) { - this(propertiesFile, StandardCharsets.ISO_8859_1); + this(propertiesFile, null); } /** * 构造 * * @param propertiesFile 配置文件对象 - * @param charsetName 字符集 - */ - public Props(final File propertiesFile, final String charsetName) { - this(propertiesFile, Charset.forName(charsetName)); - } - - /** - * 构造 - * - * @param propertiesFile 配置文件对象 - * @param charset 字符集 + * @param charset 自定义编码 */ public Props(final File propertiesFile, final Charset charset) { Assert.notNull(propertiesFile, "Null properties file!"); - this.charset = charset; - this.load(new FileResource(propertiesFile)); - } - - /** - * 构造,相对于classes读取文件 - * - * @param path 相对路径 - * @param clazz 基准类 - */ - public Props(final String path, final Class clazz) { - this(path, clazz, CharsetUtil.NAME_ISO_8859_1); - } - - /** - * 构造,相对于classes读取文件 - * - * @param path 相对路径 - * @param clazz 基准类 - * @param charsetName 字符集 - */ - public Props(final String path, final Class clazz, final String charsetName) { - this(path, clazz, CharsetUtil.charset(charsetName)); - } - - /** - * 构造,相对于classes读取文件 - * - * @param path 相对路径 - * @param clazz 基准类 - * @param charset 字符集 - */ - public Props(final String path, final Class clazz, final Charset charset) { - Assert.notBlank(path, "Blank properties file path !"); if (null != charset) { this.charset = charset; } - this.load(new ClassPathResource(path, clazz)); + this.load(ResourceUtil.getResource(propertiesFile)); } /** * 构造,使用URL读取 * - * @param propertiesUrl 属性文件路径 + * @param resource {@link Resource} + * @param charset 自定义编码 */ - public Props(final URL propertiesUrl) { - this(propertiesUrl, StandardCharsets.ISO_8859_1); - } - - /** - * 构造,使用URL读取 - * - * @param propertiesUrl 属性文件路径 - * @param charsetName 字符集 - */ - public Props(final URL propertiesUrl, final String charsetName) { - this(propertiesUrl, CharsetUtil.charset(charsetName)); - } - - /** - * 构造,使用URL读取 - * - * @param propertiesUrl 属性文件路径 - * @param charset 字符集 - */ - public Props(final URL propertiesUrl, final Charset charset) { - Assert.notNull(propertiesUrl, "Null properties URL !"); + public Props(final Resource resource, final Charset charset) { + Assert.notNull(resource, "Null properties URL !"); if (null != charset) { this.charset = charset; } - this.load(propertiesUrl); + this.load(resource); } /** @@ -316,167 +225,9 @@ public final class Props extends Properties implements BasicTypeGetter, } } - // ----------------------------------------------------------------------- Get start @Override - public Object getObj(final String key, final Object defaultValue) { - return getStr(key, null == defaultValue ? null : defaultValue.toString()); - } - - @Override - public Object getObj(final String key) { - return getObj(key, null); - } - - @Override - public String getStr(final String key, final String defaultValue) { - return super.getProperty(key, defaultValue); - } - - @Override - public String getStr(final String key) { - return super.getProperty(key); - } - - @Override - public Integer getInt(final String key, final Integer defaultValue) { - return Convert.toInt(getStr(key), defaultValue); - } - - @Override - public Integer getInt(final String key) { - return getInt(key, null); - } - - @Override - public Boolean getBool(final String key, final Boolean defaultValue) { - return Convert.toBool(getStr(key), defaultValue); - } - - @Override - public Boolean getBool(final String key) { - return getBool(key, null); - } - - @Override - public Long getLong(final String key, final Long defaultValue) { - return Convert.toLong(getStr(key), defaultValue); - } - - @Override - public Long getLong(final String key) { - return getLong(key, null); - } - - @Override - public Character getChar(final String key, final Character defaultValue) { - final String value = getStr(key); - if (StrUtil.isBlank(value)) { - return defaultValue; - } - return value.charAt(0); - } - - @Override - public Character getChar(final String key) { - return getChar(key, null); - } - - @Override - public Float getFloat(final String key) { - return getFloat(key, null); - } - - @Override - public Float getFloat(final String key, final Float defaultValue) { - return Convert.toFloat(getStr(key), defaultValue); - } - - @Override - public Double getDouble(final String key, final Double defaultValue) throws NumberFormatException { - return Convert.toDouble(getStr(key), defaultValue); - } - - @Override - public Double getDouble(final String key) throws NumberFormatException { - return getDouble(key, null); - } - - @Override - public Short getShort(final String key, final Short defaultValue) { - return Convert.toShort(getStr(key), defaultValue); - } - - @Override - public Short getShort(final String key) { - return getShort(key, null); - } - - @Override - public Byte getByte(final String key, final Byte defaultValue) { - return Convert.toByte(getStr(key), defaultValue); - } - - @Override - public Byte getByte(final String key) { - return getByte(key, null); - } - - @Override - public BigDecimal getBigDecimal(final String key, final BigDecimal defaultValue) { - final String valueStr = getStr(key); - if (StrUtil.isBlank(valueStr)) { - return defaultValue; - } - - try { - return new BigDecimal(valueStr); - } catch (final Exception e) { - return defaultValue; - } - } - - @Override - public BigDecimal getBigDecimal(final String key) { - return getBigDecimal(key, null); - } - - @Override - public BigInteger getBigInteger(final String key, final BigInteger defaultValue) { - final String valueStr = getStr(key); - if (StrUtil.isBlank(valueStr)) { - return defaultValue; - } - - try { - return new BigInteger(valueStr); - } catch (final Exception e) { - return defaultValue; - } - } - - @Override - public BigInteger getBigInteger(final String key) { - return getBigInteger(key, null); - } - - @Override - public > E getEnum(final Class clazz, final String key, final E defaultValue) { - return Convert.toEnum(clazz, getStr(key), defaultValue); - } - - @Override - public > E getEnum(final Class clazz, final String key) { - return getEnum(clazz, key, null); - } - - @Override - public Date getDate(final String key, final Date defaultValue) { - return Convert.toDate(getStr(key), defaultValue); - } - - @Override - public Date getDate(final String key) { - return getDate(key, null); + public Object getObj(final CharSequence key, final Object defaultValue) { + return ObjUtil.defaultIfNull(getProperty(StrUtil.str(key)), defaultValue); } /** diff --git a/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java b/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java index 7cf081368..2fbeaa19d 100644 --- a/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java +++ b/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java @@ -1,8 +1,6 @@ package cn.hutool.setting; import cn.hutool.core.date.DateUtil; -import cn.hutool.log.LogFactory; -import cn.hutool.log.dialect.console.ConsoleLogFactory; import cn.hutool.setting.dialect.Props; import lombok.Data; import org.junit.Assert; @@ -16,7 +14,7 @@ import java.util.Map; import java.util.Objects; /** - * Setting单元测试 + * Props单元测试 * * @author Looly * @@ -25,7 +23,7 @@ public class PropsTest { @Before public void init() { - LogFactory.setCurrentLogFactory(ConsoleLogFactory.class); + //LogFactory.setCurrentLogFactory(ConsoleLogFactory.class); } @Test @@ -53,7 +51,7 @@ public class PropsTest { @Test public void toBeanTest() { - final Props props = Props.getProp("to_bean_test.properties"); + final Props props = Props.of("to_bean_test.properties"); final ConfigProperties cfg = props.toBean(ConfigProperties.class, "mail"); Assert.assertEquals("mailer@mail.com", cfg.getHost()); diff --git a/hutool-setting/src/test/java/cn/hutool/setting/SettingTest.java b/hutool-setting/src/test/java/cn/hutool/setting/SettingTest.java index 2d66b21d7..22992393d 100644 --- a/hutool-setting/src/test/java/cn/hutool/setting/SettingTest.java +++ b/hutool-setting/src/test/java/cn/hutool/setting/SettingTest.java @@ -17,15 +17,15 @@ public class SettingTest { //noinspection MismatchedQueryAndUpdateOfCollection final Setting setting = new Setting("test.setting", true); - final String driver = setting.getByGroup("driver", "demo"); + final String driver = setting.getStrByGroup("driver", "demo"); Assert.assertEquals("com.mysql.jdbc.Driver", driver); //本分组变量替换 - final String user = setting.getByGroup("user", "demo"); + final String user = setting.getStrByGroup("user", "demo"); Assert.assertEquals("rootcom.mysql.jdbc.Driver", user); //跨分组变量替换 - final String user2 = setting.getByGroup("user2", "demo"); + final String user2 = setting.getStrByGroup("user2", "demo"); Assert.assertEquals("rootcom.mysql.jdbc.Driver", user2); //默认值测试 @@ -50,9 +50,9 @@ public class SettingTest { setting.setByGroup("user", "group3", "root3"); setting.set("user", "root4"); - Assert.assertEquals("root", setting.getByGroup("user", "group1")); - Assert.assertEquals("root2", setting.getByGroup("user", "group2")); - Assert.assertEquals("root3", setting.getByGroup("user", "group3")); + Assert.assertEquals("root", setting.getStrByGroup("user", "group1")); + Assert.assertEquals("root2", setting.getStrByGroup("user", "group2")); + Assert.assertEquals("root3", setting.getStrByGroup("user", "group3")); Assert.assertEquals("root4", setting.get("user")); } diff --git a/hutool-setting/src/test/java/cn/hutool/setting/SettingUtilTest.java b/hutool-setting/src/test/java/cn/hutool/setting/SettingUtilTest.java index 7bab45428..b3be1fe6c 100644 --- a/hutool-setting/src/test/java/cn/hutool/setting/SettingUtilTest.java +++ b/hutool-setting/src/test/java/cn/hutool/setting/SettingUtilTest.java @@ -7,13 +7,13 @@ public class SettingUtilTest { @Test public void getTest() { - final String driver = SettingUtil.get("test").get("demo", "driver"); + final String driver = SettingUtil.get("test").getStrByGroup("driver", "demo"); Assert.assertEquals("com.mysql.jdbc.Driver", driver); } @Test public void getTest2() { - final String driver = SettingUtil.get("example/example").get("demo", "key"); + final String driver = SettingUtil.get("example/example").getStrByGroup("key", "demo"); Assert.assertEquals("value", driver); } @@ -21,7 +21,7 @@ public class SettingUtilTest { public void getFirstFoundTest() { //noinspection ConstantConditions final String driver = SettingUtil.getFirstFound("test2", "test") - .get("demo", "driver"); + .getStrByGroup("driver", "demo"); Assert.assertEquals("com.mysql.jdbc.Driver", driver); } } From 47c0ce26f6e0bd874be0b1a9606f57ccebe2fecd Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 22 Sep 2022 02:36:17 +0800 Subject: [PATCH 25/73] fix doc --- .../src/main/java/cn/hutool/core/util/EnumUtil.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java index 03f31f47a..1e7607b5b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java @@ -251,13 +251,15 @@ public class EnumUtil { /** * 通过 某字段对应值 获取 枚举,获取不到时为 {@code defaultEnum} * - * @param condition 条件字段 - * @param value 条件字段值 - * @param defaultEnum 条件找不到则返回结果使用这个 + * @param condition 条件字段 + * @param value 条件字段值 + * @param defaultEnum 条件找不到则返回结果使用这个 + * @param 值类型 + * @param 枚举类型 * @return 对应枚举 ,获取不到时为 {@code null} */ public static , C> E getBy(final SerFunction condition, final C value, final E defaultEnum) { - return ObjUtil.defaultIfNull(getBy(condition,value), defaultEnum); + return ObjUtil.defaultIfNull(getBy(condition, value), defaultEnum); } /** From b61cf3c721a3f5a92d3f631d8ec44a1280e79d82 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 22 Sep 2022 02:43:57 +0800 Subject: [PATCH 26/73] fix doc --- .../hutool/core/stream/AbstractEnhancedWrappedStreamTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java index 73169ef77..88db081cb 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java @@ -628,7 +628,9 @@ public class AbstractEnhancedWrappedStreamTest { @Test public void testToEntries() { - final Map expect = new HashMap() {{ + final Map expect = new HashMap() { + private static final long serialVersionUID = 1L; + { put(1, 1); put(2, 2); put(3, 3); From 401a4cda5a27e0657676ad8eb52a4868b26564b7 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 22 Sep 2022 03:00:13 +0800 Subject: [PATCH 27/73] del setting --- .../main/java/cn/hutool/core/net/NetUtil.java | 8 ++- .../src/test/resources/config/mongo.setting | 20 ------- .../src/test/resources/config/redis.setting | 60 ------------------- .../cn/hutool/extra/qrcode/QrCodeUtil.java | 11 +++- 4 files changed, 14 insertions(+), 85 deletions(-) delete mode 100644 hutool-db/src/test/resources/config/mongo.setting delete mode 100644 hutool-db/src/test/resources/config/redis.setting diff --git a/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java index 4ff2a8284..2442e5b98 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java @@ -48,9 +48,12 @@ import java.util.function.Predicate; */ public class NetUtil { + /** + * 本地IP + */ public final static String LOCAL_IP = Ipv4Util.LOCAL_IP; - public static String localhostName; + private static String localhostName; /** * 默认最小端口,1024 @@ -841,8 +844,7 @@ public class NetUtil { } /** - * 获取DNS信息,如TXT信息: - * + * 获取DNS信息,如TXT信息:
*
 	 *     NetUtil.attrNames("hutool.cn", "TXT")
 	 * 
diff --git a/hutool-db/src/test/resources/config/mongo.setting b/hutool-db/src/test/resources/config/mongo.setting deleted file mode 100644 index b50b4d026..000000000 --- a/hutool-db/src/test/resources/config/mongo.setting +++ /dev/null @@ -1,20 +0,0 @@ -#每个主机答应的连接数(每个主机的连接池大小),当连接池被用光时,会被阻塞住 ,默以为10 --int -connectionsPerHost=100 -#线程队列数,它以connectionsPerHost值相乘的结果就是线程队列最大值。如果连接线程排满了队列就会抛出“Out of semaphores to get db”错误 --int -threadsAllowedToBlockForConnectionMultiplier=10 -#被阻塞线程从连接池获取连接的最长等待时间(ms) --int -maxWaitTime = 120000 -#在建立(打开)套接字连接时的超时时间(ms),默以为0(无穷) --int -connectTimeout=0 -#套接字超时时间;该值会被传递给Socket.setSoTimeout(int)。默以为0(无穷) --int -socketTimeout=0 -#是否打开长连接. defaults to false --boolean -socketKeepAlive=false - -#---------------------------------- MongoDB实例连接 -[master] -host = localhost:27017 - -[slave] -host = localhost:27018 -#----------------------------------------------------- diff --git a/hutool-db/src/test/resources/config/redis.setting b/hutool-db/src/test/resources/config/redis.setting deleted file mode 100644 index bf20fc0a2..000000000 --- a/hutool-db/src/test/resources/config/redis.setting +++ /dev/null @@ -1,60 +0,0 @@ -# suppress inspection "Annotator" for whole file -#---------------------------------------------------------------------------------- -# Redis客户端配置样例 -# 每一个分组代表一个Redis实例 -# 无分组的Pool配置为所有分组的共用配置,如果分组自己定义Pool配置,则覆盖共用配置 -# 池配置来自于:https://www.cnblogs.com/jklk/p/7095067.html -#---------------------------------------------------------------------------------- - -#----- 默认(公有)配置 -# 地址,默认localhost -host = localhost -# 端口,默认6379 -port = 6379 -# 超时,默认2000 -timeout = 2000 -# 连接超时,默认timeout -connectionTimeout = 2000 -# 读取超时,默认timeout -soTimeout = 2000 -# 密码,默认无 -#password = -# 数据库序号,默认0 -database = 0 -# 客户端名,默认"Hutool" -clientName = Hutool -# SSL连接,默认false -ssl = false; - -#----- 自定义分组的连接 -[custom] -# 地址,默认localhost -host = localhost -# 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -BlockWhenExhausted = true; -# 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数) -evictionPolicyClassName = org.apache.commons.pool2.impl.DefaultEvictionPolicy -# 是否启用pool的jmx管理功能, 默认true -jmxEnabled = true; -# 是否启用后进先出, 默认true -lifo = true; -# 最大空闲连接数, 默认8个 -maxIdle = 8 -# 最小空闲连接数, 默认0 -minIdle = 0 -# 最大连接数, 默认8个 -maxTotal = 8 -# 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1 -maxWaitMillis = -1 -# 逐出连接的最小空闲时间 默认1800000毫秒(30分钟) -minEvictableIdleTimeMillis = 1800000 -# 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 -numTestsPerEvictionRun = 3; -# 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略) -SoftMinEvictableIdleTimeMillis = 1800000 -# 在获取连接的时候检查有效性, 默认false -testOnBorrow = false -# 在空闲时检查有效性, 默认false -testWhileIdle = false -# 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 -timeBetweenEvictionRunsMillis = -1 diff --git a/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java index f5b5279d7..ac1461838 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java @@ -29,8 +29,14 @@ import java.util.Map; */ public class QrCodeUtil { - public static final String QR_TYPE_SVG = "svg";// SVG矢量图格式 - public static final String QR_TYPE_TXT = "txt";// Ascii Art字符画文本 + /** + * SVG矢量图格式 + */ + public static final String QR_TYPE_SVG = "svg"; + /** + * Ascii Art字符画文本 + */ + public static final String QR_TYPE_TXT = "txt"; /** * 生成代 logo 图片的 Base64 编码格式的二维码,以 String 形式表示 @@ -324,6 +330,7 @@ public class QrCodeUtil { * BitMatrix转ASCII Art字符画形式的二维码 * * @param bitMatrix BitMatrix + * @param qrConfig QR设置 * @return ASCII Art字符画形式的二维码 * @since 5.8.6 */ From d959f3a24f9266e562ceb2ad57eb9a81af58375a Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 22 Sep 2022 03:06:25 +0800 Subject: [PATCH 28/73] fix code --- hutool-swing/src/main/java/cn/hutool/swing/RobotUtil.java | 2 +- .../java/cn/hutool/swing/clipboard/ClipboardListener.java | 2 +- .../java/cn/hutool/swing/clipboard/ClipboardMonitor.java | 5 ++++- .../main/java/cn/hutool/swing/clipboard/ClipboardUtil.java | 6 +++--- .../main/java/cn/hutool/swing/clipboard/ImageSelection.java | 2 +- .../cn/hutool/swing/clipboard/StrClipboardListener.java | 2 +- .../src/test/java/cn/hutool/swing/ClipboardMonitorTest.java | 4 ++-- .../src/test/java/cn/hutool/swing/ClipboardUtilTest.java | 5 ++--- .../src/test/java/cn/hutool/swing/RobotUtilTest.java | 1 - 9 files changed, 15 insertions(+), 14 deletions(-) diff --git a/hutool-swing/src/main/java/cn/hutool/swing/RobotUtil.java b/hutool-swing/src/main/java/cn/hutool/swing/RobotUtil.java index 6f89624ee..1c57e4bd6 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/RobotUtil.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/RobotUtil.java @@ -1,8 +1,8 @@ package cn.hutool.swing; import cn.hutool.core.exceptions.UtilException; +import cn.hutool.swing.clipboard.ClipboardUtil; import cn.hutool.swing.img.ImgUtil; -import cn.hutool.core.swing.clipboard.ClipboardUtil; import java.awt.AWTException; import java.awt.Rectangle; diff --git a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardListener.java b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardListener.java index 663b953f2..57d898283 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardListener.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardListener.java @@ -1,4 +1,4 @@ -package cn.hutool.core.swing.clipboard; +package cn.hutool.swing.clipboard; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.Transferable; diff --git a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardMonitor.java b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardMonitor.java index 5f2788fa9..f4978fe82 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardMonitor.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardMonitor.java @@ -1,4 +1,4 @@ -package cn.hutool.core.swing.clipboard; +package cn.hutool.swing.clipboard; import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.ObjUtil; @@ -17,6 +17,9 @@ import java.util.Set; * @since 4.5.6 */ public enum ClipboardMonitor implements ClipboardOwner, Runnable, Closeable { + /** + * 监听器单例 + */ INSTANCE; /** 默认重试此时:10 */ diff --git a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardUtil.java b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardUtil.java index 123b3c56b..2b7108614 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardUtil.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ClipboardUtil.java @@ -1,4 +1,6 @@ -package cn.hutool.core.swing.clipboard; +package cn.hutool.swing.clipboard; + +import cn.hutool.core.exceptions.UtilException; import java.awt.Image; import java.awt.Toolkit; @@ -10,8 +12,6 @@ import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; -import cn.hutool.core.exceptions.UtilException; - /** * 系统剪贴板工具类 * diff --git a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ImageSelection.java b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ImageSelection.java index 05d58eca3..f3f696e65 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ImageSelection.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/ImageSelection.java @@ -1,4 +1,4 @@ -package cn.hutool.core.swing.clipboard; +package cn.hutool.swing.clipboard; import java.awt.Image; import java.awt.datatransfer.DataFlavor; diff --git a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/StrClipboardListener.java b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/StrClipboardListener.java index efba390e9..7f64dcf9d 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/clipboard/StrClipboardListener.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/clipboard/StrClipboardListener.java @@ -1,4 +1,4 @@ -package cn.hutool.core.swing.clipboard; +package cn.hutool.swing.clipboard; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; diff --git a/hutool-swing/src/test/java/cn/hutool/swing/ClipboardMonitorTest.java b/hutool-swing/src/test/java/cn/hutool/swing/ClipboardMonitorTest.java index de8678cd2..b099ba5bc 100755 --- a/hutool-swing/src/test/java/cn/hutool/swing/ClipboardMonitorTest.java +++ b/hutool-swing/src/test/java/cn/hutool/swing/ClipboardMonitorTest.java @@ -1,7 +1,7 @@ -package cn.hutool.core.swing; +package cn.hutool.swing; import cn.hutool.core.lang.Console; -import cn.hutool.core.swing.clipboard.ClipboardUtil; +import cn.hutool.swing.clipboard.ClipboardUtil; import org.junit.Ignore; import org.junit.Test; diff --git a/hutool-swing/src/test/java/cn/hutool/swing/ClipboardUtilTest.java b/hutool-swing/src/test/java/cn/hutool/swing/ClipboardUtilTest.java index c7110fdd7..d3692685a 100755 --- a/hutool-swing/src/test/java/cn/hutool/swing/ClipboardUtilTest.java +++ b/hutool-swing/src/test/java/cn/hutool/swing/ClipboardUtilTest.java @@ -1,10 +1,9 @@ -package cn.hutool.core.swing; +package cn.hutool.swing; +import cn.hutool.swing.clipboard.ClipboardUtil; import org.junit.Assert; import org.junit.Test; -import cn.hutool.core.swing.clipboard.ClipboardUtil; - /** * 剪贴板工具类单元测试 * diff --git a/hutool-swing/src/test/java/cn/hutool/swing/RobotUtilTest.java b/hutool-swing/src/test/java/cn/hutool/swing/RobotUtilTest.java index 553f02d71..00c32e48c 100755 --- a/hutool-swing/src/test/java/cn/hutool/swing/RobotUtilTest.java +++ b/hutool-swing/src/test/java/cn/hutool/swing/RobotUtilTest.java @@ -1,7 +1,6 @@ package cn.hutool.swing; import cn.hutool.core.io.FileUtil; -import cn.hutool.swing.RobotUtil; import org.junit.Ignore; import org.junit.Test; From ba5f1f5264aaee541347ce34b437bc19f8f62204 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 22 Sep 2022 03:33:30 +0800 Subject: [PATCH 29/73] fix code --- .../HierarchicalAnnotatedElements.java | 36 +++--- .../core/classloader/ClassLoaderUtil.java | 3 +- .../hutool/core/comparator/CompareUtil.java | 10 +- .../java/cn/hutool/core/date/DateUtil.java | 3 +- .../hutool/core/exceptions/ExceptionUtil.java | 7 +- .../java/cn/hutool/core/io/BufferUtil.java | 5 +- .../main/java/cn/hutool/core/io/FileUtil.java | 8 +- .../cn/hutool/core/io/NullOutputStream.java | 6 +- .../cn/hutool/core/io/watch/WatchMonitor.java | 3 +- .../hutool/core/lang/ansi/Ansi8BitColor.java | 12 +- .../cn/hutool/core/lang/func/SerRunnable.java | 12 +- .../hutool/core/lang/mutable/MutableInt.java | 2 +- .../cn/hutool/core/reflect/ClassUtil.java | 2 +- .../stream/AbstractEnhancedWrappedStream.java | 2 +- .../cn/hutool/core/stream/EasyStream.java | 1 - .../java/cn/hutool/core/text/CharPool.java | 2 +- .../cn/hutool/core/text/StrFormatter.java | 5 +- .../java/cn/hutool/core/text/StrPool.java | 109 ------------------ .../hutool/core/text/dfa/SensitiveUtil.java | 3 +- .../cn/hutool/core/text/split/SplitUtil.java | 2 +- .../java/cn/hutool/core/util/ArrayUtil.java | 2 +- .../java/cn/hutool/core/util/IdcardUtil.java | 2 +- .../java/cn/hutool/core/date/ZodiacTest.java | 5 +- .../hutool/core/reflect/ReflectUtilTest.java | 1 - .../java/cn/hutool/core/util/ObjUtilTest.java | 14 ++- .../cron/pattern/parser/PartParser.java | 5 +- .../db/dialect/impl/AnsiSqlDialect.java | 4 +- .../main/java/cn/hutool/db/sql/Condition.java | 2 +- .../java/cn/hutool/db/meta/MetaUtilTest.java | 2 +- .../java/cn/hutool/extra/emoji/EmojiUtil.java | 26 ++--- .../java/cn/hutool/extra/ssh/JschUtil.java | 4 +- .../cn/hutool/extra/management/OshiTest.java | 4 +- .../main/java/cn/hutool/http/HtmlUtil.java | 20 ++-- .../java/cn/hutool/http/useragent/Engine.java | 2 +- .../java/cn/hutool/json/InternalJSONUtil.java | 2 +- .../java/cn/hutool/json/JSONStrFormatter.java | 2 +- .../excel/cell/values/NumericCellValue.java | 7 +- .../java/cn/hutool/setting/PropsTest.java | 6 - .../java/cn/hutool/swing/img/ScaleType.java | 27 ++++- .../swing/img/gif/AnimatedGifEncoder.java | 8 +- 40 files changed, 143 insertions(+), 235 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java b/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java index 7959164bc..a6f06ad8e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java @@ -19,7 +19,7 @@ import java.util.stream.Stream; * 并将其包装为{@link MetaAnnotatedElement}。
* eg:
* 若存在元素A有对应父类与父接口BC, - * 则根据A生成的{@link HierarchicalAnnotatedElements}实例将同时包含ABC, + * 则根据A生成的{@code HierarchicalAnnotatedElements}实例将同时包含ABC, * 该实例同时支持对这三个实例上直接声明的注解,以及这些注解的元注解进行访问。 * *

注解搜索范围 @@ -32,7 +32,7 @@ import java.util.stream.Stream; *

  • 被保存的所有{@link AnnotatedElement}上直接声明的注解,及这些注解的元注解;
  • *
  • 若是类,则包括其所有父类和所有父接口上声明的注解和元注解;
  • *
  • - * 若是方法,且不是静态/私有/被final修饰的方法时, + * 若是方法,且不是静态/私有/被{@code final}修饰的方法时, * 则额外获取包括其声明类的所有父类和所有父接口中,与该方法具有相同方法签名的方法上的注解和元注解; *
  • * @@ -69,9 +69,9 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable /** * 创建一个分层注解元素 * - * @param element 被包装的元素,若元素已是{@link HierarchicalAnnotatedElements},则返回其本身 - * @return {@link HierarchicalAnnotatedElements}实例, - * 当{@code element}也是一个{@link HierarchicalAnnotatedElements}时,返回{@code element}本身 + * @param element 被包装的元素,若元素已是{@code HierarchicalAnnotatedElements},则返回其本身 + * @return {@code HierarchicalAnnotatedElements}实例, + * 当{@code element}也是一个{@code HierarchicalAnnotatedElements}时,返回{@code element}本身 */ public static HierarchicalAnnotatedElements create(final AnnotatedElement element) { return create(element, (es, e) -> e); @@ -80,10 +80,10 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable /** * 创建一个分层注解元素 * - * @param element 被包装的元素,若元素已是{@link HierarchicalAnnotatedElements},则返回其本身 + * @param element 被包装的元素,若元素已是{@code HierarchicalAnnotatedElements},则返回其本身 * @param elementFactory 创建{@link AnnotatedElement}的工厂方法,当返回{@code null}时将忽略该元素 - * @return {@link HierarchicalAnnotatedElements}实例, - * 当{@code element}也是一个{@link HierarchicalAnnotatedElements}时,返回{@code element}本身 + * @return {@code HierarchicalAnnotatedElements}实例, + * 当{@code element}也是一个{@code HierarchicalAnnotatedElements}时,返回{@code element}本身 */ public static HierarchicalAnnotatedElements create( final AnnotatedElement element, @@ -156,8 +156,6 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable * @param 注解类型 * @return 注解对象 */ - @SuppressWarnings("unchecked") - @Override public A[] getAnnotationsByType(final Class annotationType) { return getElementMappings().stream() .map(e -> e.getAnnotationsByType(annotationType)) @@ -239,14 +237,14 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable * @return 是否 */ @Override - public boolean equals(Object o) { + public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } - HierarchicalAnnotatedElements that = (HierarchicalAnnotatedElements)o; + final HierarchicalAnnotatedElements that = (HierarchicalAnnotatedElements)o; return elementFactory.equals(that.elementFactory) && source.equals(that.source); } @@ -294,8 +292,8 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable /** * 将元素转为{@link MetaAnnotatedElement}后添加至{@code mappings} */ - private void collectElement(Set elements, final AnnotatedElement element) { - AnnotatedElement target = elementFactory.apply(elements, element); + private void collectElement(final Set elements, final AnnotatedElement element) { + final AnnotatedElement target = elementFactory.apply(elements, element); if (Objects.nonNull(target)) { elements.add(target); } @@ -309,7 +307,7 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable if (Objects.isNull(elementMappings)) { synchronized (this) { if (Objects.isNull(elementMappings)) { - Set mappings = initElementMappings(); + final Set mappings = initElementMappings(); elementMappings = Collections.unmodifiableSet(mappings); } } @@ -320,7 +318,7 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable * 遍历层级结构,获取层级结构中所有关联的{@link AnnotatedElement},并添加到{@link #elementMappings} */ private Set initElementMappings() { - Set mappings = new LinkedHashSet<>(); + final Set mappings = new LinkedHashSet<>(); // 原始元素是类 if (source instanceof Class) { scanHierarchy(mappings, (Class)source, false, source); @@ -344,8 +342,8 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable * 按广度优先,遍历{@code type}的父类以及父接口,并从类上/类中指定方法上获得所需的注解 */ private void scanHierarchy( - Set mappings, Class type, final boolean isMethod, final AnnotatedElement source) { - Method methodSource = isMethod ? (Method)source : null; + final Set mappings, Class type, final boolean isMethod, final AnnotatedElement source) { + final Method methodSource = isMethod ? (Method)source : null; final Deque> deque = new LinkedList<>(); deque.addLast(type); final Set> accessed = new HashSet<>(); @@ -379,7 +377,7 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable *
  • 该类不为{@link Object};
  • * */ - private boolean isNeedMapping(Class type, Set> accessedTypes) { + private boolean isNeedMapping(final Class type, final Set> accessedTypes) { return Objects.nonNull(type) && !accessedTypes.contains(type) && !Objects.equals(type, Object.class); diff --git a/hutool-core/src/main/java/cn/hutool/core/classloader/ClassLoaderUtil.java b/hutool-core/src/main/java/cn/hutool/core/classloader/ClassLoaderUtil.java index bc0240fa6..ee9ac6530 100644 --- a/hutool-core/src/main/java/cn/hutool/core/classloader/ClassLoaderUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/classloader/ClassLoaderUtil.java @@ -8,6 +8,7 @@ import cn.hutool.core.map.SafeConcurrentHashMap; import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.text.CharPool; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; import java.io.File; import java.lang.reflect.Array; @@ -40,7 +41,7 @@ public class ClassLoaderUtil { /** * 包名分界符: '.' */ - private static final char PACKAGE_SEPARATOR = StrUtil.C_DOT; + private static final char PACKAGE_SEPARATOR = CharUtil.DOT; /** * 内部类分界符: '$' */ diff --git a/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java b/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java index 23dd47e4a..bbd723284 100644 --- a/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java @@ -98,8 +98,8 @@ public class CompareUtil { * *
      *
    • 如需对null友好操作如下
    • - *
    • Comparator.nullsLast(CompareUtil.natural())
    • - *
    • Comparator.nullsFirst(CompareUtil.natural())
    • + *
    • {@code Comparator.nullsLast(CompareUtil.natural())}
    • + *
    • {@code Comparator.nullsFirst(CompareUtil.natural())}
    • *
    * * @param 排序节点类型 @@ -115,8 +115,8 @@ public class CompareUtil { * *
      *
    • 如需对null友好操作如下
    • - *
    • Comparator.nullsLast(CompareUtil.naturalReverse())
    • - *
    • Comparator.nullsFirst(CompareUtil.naturalReverse())
    • + *
    • {@code Comparator.nullsLast(CompareUtil.naturalReverse())}
    • + *
    • {@code Comparator.nullsFirst(CompareUtil.naturalReverse())}
    • *
    * * @param 排序节点类型 @@ -314,7 +314,7 @@ public class CompareUtil { * * @param keyExtractor 从对象中提取排序键的函数(参与比较的内容) * @param atEndIfMiss 如果不在列表中是否排在后边; true:排在后边; false:排在前边 - * @param objs 参与排序的数组,数组的元素位置决定了对象的排序先后, 示例:int[] objs = new int[]{3, 2, 1, 4, 5,6}; + * @param objs 参与排序的数组,数组的元素位置决定了对象的排序先后, 示例:{@code int[] objs = new int[]{3, 2, 1, 4, 5,6};} * @param 对象类型 * @param 数组对象类型 * @return 索引比较器 diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index 917fc4a40..ab213acd9 100755 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -16,6 +16,7 @@ import cn.hutool.core.math.NumberUtil; import cn.hutool.core.regex.PatternPool; import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; import javax.xml.datatype.XMLGregorianCalendar; import java.text.DateFormat; @@ -1624,7 +1625,7 @@ public class DateUtil extends CalendarUtil { return 0; } - final List hms = StrUtil.splitTrim(timeStr, StrUtil.C_COLON, 3); + final List hms = StrUtil.splitTrim(timeStr, CharUtil.COLON, 3); final int lastIndex = hms.size() - 1; int result = 0; diff --git a/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java b/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java index 645e0cb50..ef0c0aec2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java @@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.CharUtil; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; @@ -201,9 +202,9 @@ public class ExceptionUtil { */ public static String stacktraceToOneLineString(final Throwable throwable, final int limit) { final Map replaceCharToStrMap = new HashMap<>(); - replaceCharToStrMap.put(StrUtil.C_CR, StrUtil.SPACE); - replaceCharToStrMap.put(StrUtil.C_LF, StrUtil.SPACE); - replaceCharToStrMap.put(StrUtil.C_TAB, StrUtil.SPACE); + replaceCharToStrMap.put(CharUtil.CR, StrUtil.SPACE); + replaceCharToStrMap.put(CharUtil.LF, StrUtil.SPACE); + replaceCharToStrMap.put(CharUtil.TAB, StrUtil.SPACE); return stacktraceToString(throwable, limit, replaceCharToStrMap); } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/BufferUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/BufferUtil.java index 542488a3e..910f3d36e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/BufferUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/BufferUtil.java @@ -1,5 +1,6 @@ package cn.hutool.core.io; +import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.text.StrUtil; @@ -166,9 +167,9 @@ public class BufferUtil { while (buffer.hasRemaining()) { b = buffer.get(); charIndex++; - if (b == StrUtil.C_CR) { + if (b == CharUtil.CR) { canEnd = true; - } else if (b == StrUtil.C_LF) { + } else if (b == CharUtil.LF) { return canEnd ? charIndex - 2 : charIndex - 1; } else { // 只有\r无法确认换行 diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java index 231b9319c..a5d416375 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java @@ -1306,7 +1306,7 @@ public class FileUtil extends PathUtil { } // 给定的路径已经是绝对路径了 - return StrUtil.C_SLASH == path.charAt(0) || ReUtil.isMatch(PATTERN_PATH_ABSOLUTE, path); + return CharUtil.SLASH == path.charAt(0) || ReUtil.isMatch(PATTERN_PATH_ABSOLUTE, path); } /** @@ -1600,7 +1600,7 @@ public class FileUtil extends PathUtil { if (prefixIndex > -1) { // 可能Windows风格路径 prefix = pathToUse.substring(0, prefixIndex + 1); - if (StrUtil.startWith(prefix, StrUtil.C_SLASH)) { + if (StrUtil.startWith(prefix, CharUtil.SLASH)) { // 去除类似于/C:这类路径开头的斜杠 prefix = prefix.substring(1); } @@ -1616,7 +1616,7 @@ public class FileUtil extends PathUtil { pathToUse = pathToUse.substring(1); } - final List pathList = StrUtil.split(pathToUse, StrUtil.C_SLASH); + final List pathList = StrUtil.split(pathToUse, CharUtil.SLASH); final List pathElements = new LinkedList<>(); int tops = 0; @@ -1887,6 +1887,7 @@ public class FileUtil extends PathUtil { */ public static BOMInputStream getBOMInputStream(final File file) throws IORuntimeException { try { + //noinspection IOStreamConstructor return new BOMInputStream(new FileInputStream(file)); } catch (final IOException e) { throw new IORuntimeException(e); @@ -2431,6 +2432,7 @@ public class FileUtil extends PathUtil { public static BufferedOutputStream getOutputStream(final File file) throws IORuntimeException { final OutputStream out; try { + //noinspection IOStreamConstructor out = new FileOutputStream(touch(file)); } catch (final IOException e) { throw new IORuntimeException(e); diff --git a/hutool-core/src/main/java/cn/hutool/core/io/NullOutputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/NullOutputStream.java index eb3b38e0b..6f48a8041 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/NullOutputStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/NullOutputStream.java @@ -18,7 +18,7 @@ public class NullOutputStream extends OutputStream { public static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream(); /** - * 什么也不做,写出到/dev/null. + * 什么也不做,写出到{@code /dev/null}. * * @param b 写出的数据 * @param off 开始位置 @@ -30,7 +30,7 @@ public class NullOutputStream extends OutputStream { } /** - * 什么也不做,写出到 /dev/null. + * 什么也不做,写出到 {@code /dev/null}. * * @param b 写出的数据 */ @@ -40,7 +40,7 @@ public class NullOutputStream extends OutputStream { } /** - * 什么也不做,写出到 /dev/null. + * 什么也不做,写出到 {@code /dev/null}. * * @param b 写出的数据 * @throws IOException 不抛出 diff --git a/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java b/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java index a9282531c..288d7b6d3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java @@ -5,6 +5,7 @@ import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.watch.watchers.WatcherChain; import cn.hutool.core.text.StrUtil; import cn.hutool.core.net.URLUtil; +import cn.hutool.core.util.CharUtil; import java.io.File; import java.io.IOException; @@ -322,7 +323,7 @@ public class WatchMonitor extends WatchServer { if (null != lastPathEle) { final String lastPathEleStr = lastPathEle.toString(); //带有点表示有扩展名,按照未创建的文件对待。Linux下.d的为目录,排除之 - if (StrUtil.contains(lastPathEleStr, StrUtil.C_DOT) && false == StrUtil.endWithIgnoreCase(lastPathEleStr, ".d")) { + if (StrUtil.contains(lastPathEleStr, CharUtil.DOT) && false == StrUtil.endWithIgnoreCase(lastPathEleStr, ".d")) { this.filePath = this.path; this.path = this.filePath.getParent(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/ansi/Ansi8BitColor.java b/hutool-core/src/main/java/cn/hutool/core/lang/ansi/Ansi8BitColor.java index e420b6c12..af1a50828 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/ansi/Ansi8BitColor.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/ansi/Ansi8BitColor.java @@ -30,7 +30,7 @@ public class Ansi8BitColor implements AnsiElement { * @param code 颜色代码(0-255) * @return 前景色ANSI颜色实例 */ - public static Ansi8BitColor foreground(int code) { + public static Ansi8BitColor foreground(final int code) { return new Ansi8BitColor(PREFIX_FORE, code); } @@ -40,7 +40,7 @@ public class Ansi8BitColor implements AnsiElement { * @param code 颜色代码(0-255) * @return 背景色ANSI颜色实例 */ - public static Ansi8BitColor background(int code) { + public static Ansi8BitColor background(final int code) { return new Ansi8BitColor(PREFIX_BACK, code); } @@ -52,9 +52,9 @@ public class Ansi8BitColor implements AnsiElement { * * @param prefix 前缀 * @param code 颜色代码(0-255) - * @throws IllegalArgumentException 颜色代码不在0~255范围内 + * @throws IllegalArgumentException 颜色代码不在 0~255 范围内 */ - private Ansi8BitColor(String prefix, int code) { + private Ansi8BitColor(final String prefix, final int code) { Assert.isTrue(code >= 0 && code <= 255, "Code must be between 0 and 255"); this.prefix = prefix; this.code = code; @@ -95,14 +95,14 @@ public class Ansi8BitColor implements AnsiElement { } @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } - Ansi8BitColor other = (Ansi8BitColor) obj; + final Ansi8BitColor other = (Ansi8BitColor) obj; return ObjUtil.equals(this.prefix, other.prefix) && this.code == other.code; } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerRunnable.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerRunnable.java index f9c3f9ed9..79a123509 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerRunnable.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerRunnable.java @@ -16,12 +16,12 @@ import java.util.stream.Stream; public interface SerRunnable extends Runnable, Serializable { /** - * When an object implementing interface Runnable is used + * When an object implementing interface {@code Runnable} is used * to create a thread, starting the thread causes the object's - * run method to be called in that separately executing + * {@code run} method to be called in that separately executing * thread. *

    - * The general contract of the method run is that it may + * The general contract of the method {@code run} is that it may * take any action whatsoever. * * @throws Exception wrapped checked exceptions @@ -30,12 +30,12 @@ public interface SerRunnable extends Runnable, Serializable { void running() throws Exception; /** - * When an object implementing interface Runnable is used + * When an object implementing interface {@code Runnable} is used * to create a thread, starting the thread causes the object's - * run method to be called in that separately executing + * {@code run} method to be called in that separately executing * thread. *

    - * The general contract of the method run is that it may + * The general contract of the method {@code run} is that it may * take any action whatsoever. * * @see Thread#run() diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java index 9cb300af5..7c1c773c8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java @@ -3,7 +3,7 @@ package cn.hutool.core.lang.mutable; import cn.hutool.core.comparator.CompareUtil; /** - * 可变 int 类型 + * 可变 {@code int} 类型 * * @see Integer * @since 3.0.1 diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java index a86c2b986..39e1d8baf 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java @@ -544,7 +544,7 @@ public class ClassUtil { * @return 包名 */ public static String getPackagePath(final Class clazz) { - return getPackage(clazz).replace(StrUtil.C_DOT, StrUtil.C_SLASH); + return getPackage(clazz).replace(CharUtil.DOT, CharUtil.SLASH); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/AbstractEnhancedWrappedStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/AbstractEnhancedWrappedStream.java index 687d47ea8..122b7b9c9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/AbstractEnhancedWrappedStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/AbstractEnhancedWrappedStream.java @@ -17,7 +17,7 @@ public abstract class AbstractEnhancedWrappedStream, TransformableWrappedStream { /** - * 原始的流实例 + * 原始流实例 */ protected final Stream stream; diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index b892b7199..5de51cdbf 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -4,7 +4,6 @@ import cn.hutool.core.lang.Opt; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; -import java.util.List; import java.util.Objects; import java.util.Spliterator; import java.util.function.*; diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java b/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java index bc764bfa2..934af9605 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java @@ -2,7 +2,7 @@ package cn.hutool.core.text; /** * 常用字符常量 - * @see StrPool + * * @author looly * @since 5.6.3 */ diff --git a/hutool-core/src/main/java/cn/hutool/core/text/StrFormatter.java b/hutool-core/src/main/java/cn/hutool/core/text/StrFormatter.java index 7c19424d5..3c1517a0e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/StrFormatter.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/StrFormatter.java @@ -1,6 +1,7 @@ package cn.hutool.core.text; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.CharUtil; import java.util.Map; @@ -67,8 +68,8 @@ public class StrFormatter { } // 转义符 - if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == StrUtil.C_BACKSLASH) {// 转义符 - if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == StrUtil.C_BACKSLASH) {// 双转义符 + if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == CharUtil.BACKSLASH) {// 转义符 + if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == CharUtil.BACKSLASH) {// 双转义符 // 转义符之前还有一个转义符,占位符依旧有效 sbuf.append(strPattern, handledPosition, delimIndex - 1); sbuf.append(StrUtil.utf8Str(argArray[argIndex])); diff --git a/hutool-core/src/main/java/cn/hutool/core/text/StrPool.java b/hutool-core/src/main/java/cn/hutool/core/text/StrPool.java index 743c4e474..2714e0492 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/StrPool.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/StrPool.java @@ -1,7 +1,5 @@ package cn.hutool.core.text; -import cn.hutool.core.util.XmlUtil; - /** * 常用字符串常量定义 * @see CharPool @@ -10,82 +8,6 @@ import cn.hutool.core.util.XmlUtil; * @since 5.6.3 */ public interface StrPool { - - /** - * 字符常量:空格符 {@code ' '} - */ - char C_SPACE = CharPool.SPACE; - - /** - * 字符常量:制表符 {@code '\t'} - */ - char C_TAB = CharPool.TAB; - - /** - * 字符常量:点 {@code '.'} - */ - char C_DOT = CharPool.DOT; - - /** - * 字符常量:斜杠 {@code '/'} - */ - char C_SLASH = CharPool.SLASH; - - /** - * 字符常量:反斜杠 {@code '\\'} - */ - char C_BACKSLASH = CharPool.BACKSLASH; - - /** - * 字符常量:回车符 {@code '\r'} - */ - char C_CR = CharPool.CR; - - /** - * 字符常量:换行符 {@code '\n'} - */ - char C_LF = CharPool.LF; - - /** - * 字符常量:下划线 {@code '_'} - */ - char C_UNDERLINE = CharPool.UNDERLINE; - - /** - * 字符常量:逗号 {@code ','} - */ - char C_COMMA = CharPool.COMMA; - - /** - * 字符常量:花括号(左) '{' - */ - char C_DELIM_START = CharPool.DELIM_START; - - /** - * 字符常量:花括号(右) '}' - */ - char C_DELIM_END = CharPool.DELIM_END; - - /** - * 字符常量:中括号(左) {@code '['} - */ - char C_BRACKET_START = CharPool.BRACKET_START; - - /** - * 字符常量:中括号(右) {@code ']'} - */ - char C_BRACKET_END = CharPool.BRACKET_END; - - /** - * 字符常量:冒号 {@code ':'} - */ - char C_COLON = CharPool.COLON; - - /** - * 字符常量:艾特 {@code '@'} - */ - char C_AT = CharPool.AT; - /** * 字符串常量:制表符 {@code "\t"} */ @@ -174,37 +96,6 @@ public interface StrPool { */ String AT = "@"; - - /** - * 字符串常量:HTML 空格转义 {@code " " -> " "} - */ - String HTML_NBSP = XmlUtil.NBSP; - - /** - * 字符串常量:HTML And 符转义 {@code "&" -> "&"} - */ - String HTML_AMP = XmlUtil.AMP; - - /** - * 字符串常量:HTML 双引号转义 {@code """ -> "\""} - */ - String HTML_QUOTE = XmlUtil.QUOTE; - - /** - * 字符串常量:HTML 单引号转义 {@code "&apos" -> "'"} - */ - String HTML_APOS = XmlUtil.APOS; - - /** - * 字符串常量:HTML 小于号转义 {@code "<" -> "<"} - */ - String HTML_LT = XmlUtil.LT; - - /** - * 字符串常量:HTML 大于号转义 {@code ">" -> ">"} - */ - String HTML_GT = XmlUtil.GT; - /** * 字符串常量:空 JSON {@code "{}"} */ diff --git a/hutool-core/src/main/java/cn/hutool/core/text/dfa/SensitiveUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/dfa/SensitiveUtil.java index 499308021..07e1cb64e 100755 --- a/hutool-core/src/main/java/cn/hutool/core/text/dfa/SensitiveUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/dfa/SensitiveUtil.java @@ -3,6 +3,7 @@ package cn.hutool.core.text.dfa; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; import java.util.Collection; import java.util.HashMap; @@ -17,7 +18,7 @@ import java.util.function.Predicate; */ public final class SensitiveUtil { - public static final char DEFAULT_SEPARATOR = StrUtil.C_COMMA; + public static final char DEFAULT_SEPARATOR = CharUtil.COMMA; private static final WordTree sensitiveTree = new WordTree(); /** diff --git a/hutool-core/src/main/java/cn/hutool/core/text/split/SplitUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/split/SplitUtil.java index e385f1f9a..6a16f86de 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/split/SplitUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/split/SplitUtil.java @@ -54,7 +54,7 @@ public class SplitUtil { * @since 3.0.8 */ public static List splitPath(final CharSequence str, final int limit) { - return split(str, StrUtil.C_SLASH, limit, true, true); + return split(str, CharUtil.SLASH, limit, true, true); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java index cc7c377c5..530656cd4 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java @@ -64,7 +64,7 @@ public class ArrayUtil extends PrimitiveArrayUtil { * 数组是否为空
    * 此方法会匹配单一对象,如果此对象为{@code null}则返回true
    * 如果此对象为非数组,理解为此对象为数组的第一个元素,则返回false
    - * 如果此对象为数组对象,数组长度大于0情况下返回false,否则返回true + * 如果此对象为数组对象,数组长度大于0的情况下返回false,否则返回true * * @param array 数组 * @return 是否为空 diff --git a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java index 497e26b24..45cdb8451 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java @@ -708,7 +708,7 @@ public class IdcardUtil { case 0: return '1'; default: - return StrUtil.C_SPACE; + return CharUtil.SPACE; } } diff --git a/hutool-core/src/test/java/cn/hutool/core/date/ZodiacTest.java b/hutool-core/src/test/java/cn/hutool/core/date/ZodiacTest.java index bbe1eac5c..07479928e 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/ZodiacTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/ZodiacTest.java @@ -4,7 +4,6 @@ import org.junit.Assert; import org.junit.Test; import java.util.Calendar; -import java.util.Date; public class ZodiacTest { @@ -13,7 +12,7 @@ public class ZodiacTest { Assert.assertEquals("摩羯座", Zodiac.getZodiac(Month.JANUARY, 19)); Assert.assertEquals("水瓶座", Zodiac.getZodiac(Month.JANUARY, 20)); Assert.assertEquals("巨蟹座", Zodiac.getZodiac(6, 17)); - Calendar calendar = Calendar.getInstance(); + final Calendar calendar = Calendar.getInstance(); calendar.set(2022, Calendar.JULY, 17); Assert.assertEquals("巨蟹座", Zodiac.getZodiac(calendar.getTime())); Assert.assertEquals("巨蟹座", Zodiac.getZodiac(calendar)); @@ -25,7 +24,7 @@ public class ZodiacTest { Assert.assertEquals("狗", Zodiac.getChineseZodiac(1994)); Assert.assertEquals("狗", Zodiac.getChineseZodiac(2018)); Assert.assertEquals("猪", Zodiac.getChineseZodiac(2019)); - Calendar calendar = Calendar.getInstance(); + final Calendar calendar = Calendar.getInstance(); calendar.set(2022, Calendar.JULY, 17); Assert.assertEquals("虎", Zodiac.getChineseZodiac(calendar.getTime())); Assert.assertEquals("虎", Zodiac.getChineseZodiac(calendar)); diff --git a/hutool-core/src/test/java/cn/hutool/core/reflect/ReflectUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/reflect/ReflectUtilTest.java index 60d2bdbb8..d60e5379d 100644 --- a/hutool-core/src/test/java/cn/hutool/core/reflect/ReflectUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/reflect/ReflectUtilTest.java @@ -6,7 +6,6 @@ import lombok.SneakyThrows; import org.junit.Test; import java.util.Arrays; -import java.util.Collection; /** * 反射工具类单元测试 diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ObjUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ObjUtilTest.java index d72c36c65..cb6a25aa1 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/ObjUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ObjUtilTest.java @@ -70,18 +70,20 @@ public class ObjUtilTest { Assert.assertTrue(ObjUtil.contains(new int[]{1,2,3,4,5}, 1)); Assert.assertFalse(ObjUtil.contains(null, 1)); Assert.assertTrue(ObjUtil.contains("123", "3")); - Map map = new HashMap<>(); + final Map map = new HashMap<>(); map.put(1, 1); map.put(2, 2); Assert.assertTrue(ObjUtil.contains(map, 1)); Assert.assertTrue(ObjUtil.contains(Arrays.asList(1, 2, 3).iterator(), 2)); } + @SuppressWarnings("ConstantConditions") @Test public void isNullTest() { Assert.assertTrue(ObjUtil.isNull(null)); } + @SuppressWarnings("ConstantConditions") @Test public void isNotNullTest() { Assert.assertFalse(ObjUtil.isNotNull(null)); @@ -124,12 +126,12 @@ public class ObjUtilTest { Assert.assertSame(val1, ObjUtil.defaultIfNull(val1, Function.identity(), val2)); Assert.assertSame(val2, ObjUtil.defaultIfNull(null, Function.identity(), val2)); - SerializableBean obj = new SerializableBean(null); - SerializableBean objNull = null; - String result3 = ObjUtil.defaultIfNull(obj, Object::toString, "fail"); + final SerializableBean obj = new SerializableBean(null); + final SerializableBean objNull = null; + final String result3 = ObjUtil.defaultIfNull(obj, Object::toString, "fail"); Assert.assertNotNull(result3); - String result4 = ObjUtil.defaultIfNull(objNull, Object::toString, () -> "fail"); + final String result4 = ObjUtil.defaultIfNull(objNull, Object::toString, () -> "fail"); Assert.assertNotNull(result4); } @@ -242,6 +244,7 @@ public class ObjUtilTest { @RequiredArgsConstructor @EqualsAndHashCode private static class SerializableBean implements Serializable { + private static final long serialVersionUID = -7759522980793544334L; private final Integer id; } @@ -251,6 +254,7 @@ public class ObjUtilTest { private final Integer id; } + @SuppressWarnings("unused") private interface TypeArgument {}; } diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java index 70cad5597..ce3c10784 100644 --- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java +++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java @@ -5,6 +5,7 @@ import cn.hutool.core.date.Month; import cn.hutool.core.date.Week; import cn.hutool.core.math.NumberUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; import cn.hutool.cron.CronException; import cn.hutool.cron.pattern.Part; import cn.hutool.cron.pattern.matcher.AlwaysTrueMatcher; @@ -102,7 +103,7 @@ public class PartParser { private List parseArray(final String value) { final List values = new ArrayList<>(); - final List parts = StrUtil.split(value, StrUtil.C_COMMA); + final List parts = StrUtil.split(value, CharUtil.COMMA); for (final String part : parts) { ListUtil.addAllIfNotContains(values, parseStep(part)); } @@ -122,7 +123,7 @@ public class PartParser { * @return List */ private List parseStep(final String value) { - final List parts = StrUtil.split(value, StrUtil.C_SLASH); + final List parts = StrUtil.split(value, CharUtil.SLASH); final int size = parts.size(); final List results; diff --git a/hutool-db/src/main/java/cn/hutool/db/dialect/impl/AnsiSqlDialect.java b/hutool-db/src/main/java/cn/hutool/db/dialect/impl/AnsiSqlDialect.java index b3eee952c..3553cbb7a 100644 --- a/hutool-db/src/main/java/cn/hutool/db/dialect/impl/AnsiSqlDialect.java +++ b/hutool-db/src/main/java/cn/hutool/db/dialect/impl/AnsiSqlDialect.java @@ -65,7 +65,7 @@ public class AnsiSqlDialect implements Dialect { final Condition[] where = query.getWhere(); if (ArrayUtil.isEmpty(where)) { - // 对于无条件的删除语句直接抛出异常禁止,防止误删除 + // 对于无条件删除语句直接抛出异常禁止,防止误删除 throw new SQLException("No 'WHERE' condition, we can't prepared statement for delete everything."); } final SqlBuilder delete = SqlBuilder.of(wrapper).delete(query.getFirstTableName()).where(where); @@ -79,7 +79,7 @@ public class AnsiSqlDialect implements Dialect { final Condition[] where = query.getWhere(); if (ArrayUtil.isEmpty(where)) { - // 对于无条件的删除语句直接抛出异常禁止,防止误删除 + // 对于无条件地删除语句直接抛出异常禁止,防止误删除 throw new SQLException("No 'WHERE' condition, we can't prepare statement for update everything."); } diff --git a/hutool-db/src/main/java/cn/hutool/db/sql/Condition.java b/hutool-db/src/main/java/cn/hutool/db/sql/Condition.java index 2243ee2bd..3c2da0a6b 100644 --- a/hutool-db/src/main/java/cn/hutool/db/sql/Condition.java +++ b/hutool-db/src/main/java/cn/hutool/db/sql/Condition.java @@ -490,7 +490,7 @@ public class Condition implements Cloneable, Serializable { } } - final List strs = StrUtil.split(valueStr, StrUtil.C_SPACE, 2); + final List strs = StrUtil.split(valueStr, CharUtil.SPACE, 2); if (strs.size() < 2) { return; } diff --git a/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java b/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java index 0c5f65dd4..43f64eee2 100644 --- a/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java +++ b/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java @@ -16,7 +16,7 @@ import java.util.List; * */ public class MetaUtilTest { - DataSource ds = DSFactory.get("test"); + final DataSource ds = DSFactory.get("test"); @Test public void getTablesTest() { diff --git a/hutool-extra/src/main/java/cn/hutool/extra/emoji/EmojiUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/emoji/EmojiUtil.java index 06600b630..c9dfebaa2 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/emoji/EmojiUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/emoji/EmojiUtil.java @@ -11,7 +11,7 @@ import java.util.Set; /** * 基于https://github.com/vdurmont/emoji-java的Emoji表情工具类 *

    -	 *  :smile:  替换为 😄
    -	 * &#128516; 替换为 😄
    -	 * :boy|type_6: 替换为 👦🏿
    +	 *  {@code :smile:}  替换为 {@code 😄}
    +	 * {@code 😄} 替换为 {@code 😄}
    +	 * {@code :boy|type_6:} 替换为 {@code 👦🏿}
     	 * 
    * * @param str 包含Emoji别名或者HTML表现形式的字符串 @@ -80,22 +80,22 @@ public class EmojiUtil { /** * 将字符串中的Unicode Emoji字符转换为别名表现形式(两个":"包围的格式) *

    - * 例如: 😄 转换为 :smile: + * 例如: {@code 😄} 转换为 {@code :smile:} * *

    * {@link FitzpatrickAction}参数被设置为{@link FitzpatrickAction#PARSE},则别名后会增加"|"并追加fitzpatrick类型 *

    - * 例如:👦🏿 转换为 :boy|type_6: + * 例如:{@code 👦🏿} 转换为 {@code :boy|type_6:} * *

    * {@link FitzpatrickAction}参数被设置为{@link FitzpatrickAction#REMOVE},则别名后的"|"和类型将被去除 *

    - * 例如:👦🏿 转换为 :boy: + * 例如:{@code 👦🏿} 转换为 {@code :boy:} * *

    * {@link FitzpatrickAction}参数被设置为{@link FitzpatrickAction#IGNORE},则别名后的类型将被忽略 *

    - * 例如:👦🏿 转换为 :boy:🏿 + * 例如:{@code 👦🏿} 转换为 {@code :boy:🏿} * * @param str 包含Emoji Unicode字符的字符串 * @return 替换后的字符串 @@ -107,7 +107,7 @@ public class EmojiUtil { /** * 将字符串中的Unicode Emoji字符转换为别名表现形式(两个":"包围的格式),别名后会增加"|"并追加fitzpatrick类型 *

    - * 例如:👦🏿 转换为 :boy|type_6: + * 例如:{@code 👦🏿} 转换为 {@code :boy|type_6:} * * @param str 包含Emoji Unicode字符的字符串 * @param fitzpatrickAction {@link FitzpatrickAction} @@ -120,7 +120,7 @@ public class EmojiUtil { /** * 将字符串中的Unicode Emoji字符转换为HTML 16进制表现形式 *

    - * 例如:👦🏿 转换为 &#x1f466; + * 例如:{@code 👦🏿} 转换为 {@code 👦} * * @param str 包含Emoji Unicode字符的字符串 * @return 替换后的字符串 @@ -132,7 +132,7 @@ public class EmojiUtil { /** * 将字符串中的Unicode Emoji字符转换为HTML表现形式(Hex方式) *

    - * 例如:👦🏿 转换为 &#128102; + * 例如:{@code 👦🏿} 转换为 {@code 👦} * * @param str 包含Emoji Unicode字符的字符串 * @return 替换后的字符串 @@ -144,8 +144,8 @@ public class EmojiUtil { /** * 将字符串中的Unicode Emoji字符转换为HTML表现形式,例如: *

    -	 * 如果为hex形式,👦🏿 转换为 &#x1f466;
    -	 * 否则,👦🏿 转换为 &#128102;
    +	 * 如果为hex形式,{@code 👦🏿} 转换为 {@code 👦}
    +	 * 否则,{@code 👦🏿} 转换为 {@code 👦}
     	 * 
    * * @param str 包含Emoji Unicode字符的字符串 diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java index d053c0b2a..1421077fc 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java @@ -296,15 +296,13 @@ public class JschUtil { * * @param session 需要解除端口映射的SSH会话 * @param localPort 需要解除的本地端口 - * @return 解除成功与否 */ - public static boolean unBindPort(final Session session, final int localPort) { + public static void unBindPort(final Session session, final int localPort) { try { session.delPortForwardingL(localPort); } catch (final JSchException e) { throw new JschRuntimeException(e); } - return true; } /** diff --git a/hutool-extra/src/test/java/cn/hutool/extra/management/OshiTest.java b/hutool-extra/src/test/java/cn/hutool/extra/management/OshiTest.java index c028c8166..ce1fec97b 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/management/OshiTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/management/OshiTest.java @@ -34,8 +34,10 @@ public class OshiTest { @Test @Ignore public void getUsedTest() { - while (true) { + int i = 0; + while (i < 1000) { Console.log(OshiUtil.getCpuInfo().getUsed()); + i++; } } } diff --git a/hutool-http/src/main/java/cn/hutool/http/HtmlUtil.java b/hutool-http/src/main/java/cn/hutool/http/HtmlUtil.java index 21ad44145..2ebbe8cd5 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HtmlUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/HtmlUtil.java @@ -1,8 +1,9 @@ package cn.hutool.http; -import cn.hutool.core.text.escape.EscapeUtil; import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.text.escape.EscapeUtil; +import cn.hutool.core.util.XmlUtil; /** * HTML工具类 @@ -16,14 +17,7 @@ import cn.hutool.core.text.StrUtil; */ public class HtmlUtil { - public static final String NBSP = StrUtil.HTML_NBSP; - public static final String AMP = StrUtil.HTML_AMP; - public static final String QUOTE = StrUtil.HTML_QUOTE; - public static final String APOS = StrUtil.HTML_APOS; - public static final String LT = StrUtil.HTML_LT; - public static final String GT = StrUtil.HTML_GT; - - public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)"; + public static final String RE_HTML_MARK = "(<[^<]*?>)|(<\\s*?/[^<]*?>)|(<[^<]*?/\\s*?>)"; public static final String RE_SCRIPT = "<[\\s]*?script[^>]*?>.*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"; private static final char[][] TEXT = new char[64][]; @@ -35,10 +29,10 @@ public class HtmlUtil { // special HTML characters TEXT['\''] = "'".toCharArray(); // 单引号 (''' doesn't work - it is not by the w3 specs) - TEXT['"'] = QUOTE.toCharArray(); // 单引号 - TEXT['&'] = AMP.toCharArray(); // &符 - TEXT['<'] = LT.toCharArray(); // 小于号 - TEXT['>'] = GT.toCharArray(); // 大于号 + TEXT['"'] = XmlUtil.QUOTE.toCharArray(); // 单引号 + TEXT['&'] = XmlUtil.AMP.toCharArray(); // &符 + TEXT['<'] = XmlUtil.LT.toCharArray(); // 小于号 + TEXT['>'] = XmlUtil.GT.toCharArray(); // 大于号 } /** diff --git a/hutool-http/src/main/java/cn/hutool/http/useragent/Engine.java b/hutool-http/src/main/java/cn/hutool/http/useragent/Engine.java index 2317bd461..a5053626c 100755 --- a/hutool-http/src/main/java/cn/hutool/http/useragent/Engine.java +++ b/hutool-http/src/main/java/cn/hutool/http/useragent/Engine.java @@ -43,7 +43,7 @@ public class Engine extends UserAgentInfo { */ public Engine(final String name, final String regex) { super(name, regex); - this.versionPattern = Pattern.compile(name + "[/\\- ]([\\d\\w.\\-]+)", Pattern.CASE_INSENSITIVE); + this.versionPattern = Pattern.compile(name + "[/\\- ]([\\w.\\-]+)", Pattern.CASE_INSENSITIVE); } /** diff --git a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java index b247e08df..c39fff3b6 100755 --- a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java +++ b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java @@ -432,7 +432,7 @@ public final class InternalJSONUtil { case '\r': return "\\r"; default: - if (c < StrUtil.C_SPACE || // + if (c < CharUtil.SPACE || // (c >= '\u0080' && c <= '\u00a0') || // (c >= '\u2000' && c <= '\u2010') || // (c >= '\u2028' && c <= '\u202F') || // diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONStrFormatter.java b/hutool-json/src/main/java/cn/hutool/json/JSONStrFormatter.java index b9f33dbaa..412f23578 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONStrFormatter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONStrFormatter.java @@ -19,7 +19,7 @@ public class JSONStrFormatter { /** * 换行符 */ - private static final char NEW_LINE = StrUtil.C_LF; + private static final char NEW_LINE = CharUtil.LF; /** * 返回格式化JSON字符串。 diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/values/NumericCellValue.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/values/NumericCellValue.java index 0651b5dfb..ccab77866 100755 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/values/NumericCellValue.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/values/NumericCellValue.java @@ -1,14 +1,15 @@ package cn.hutool.poi.excel.cell.values; import cn.hutool.core.date.DateUtil; -import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; import cn.hutool.poi.excel.ExcelDateUtil; import cn.hutool.poi.excel.cell.CellValue; -import java.util.Date; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.util.NumberToTextConverter; +import java.util.Date; + /** * 数字类型单元格值
    * 单元格值可能为Long、Double、Date @@ -48,7 +49,7 @@ public class NumericCellValue implements CellValue { final String format = style.getDataFormatString(); // 普通数字 - if (null != format && format.indexOf(StrUtil.C_DOT) < 0) { + if (null != format && format.indexOf(CharUtil.DOT) < 0) { final long longPart = (long) value; if (((double) longPart) == value) { // 对于无小数部分的数字类型,转为Long diff --git a/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java b/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java index 2fbeaa19d..8a7262769 100644 --- a/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java +++ b/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java @@ -4,7 +4,6 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.setting.dialect.Props; import lombok.Data; import org.junit.Assert; -import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -21,11 +20,6 @@ import java.util.Objects; */ public class PropsTest { - @Before - public void init() { - //LogFactory.setCurrentLogFactory(ConsoleLogFactory.class); - } - @Test public void propTest() { //noinspection MismatchedQueryAndUpdateOfCollection diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/ScaleType.java b/hutool-swing/src/main/java/cn/hutool/swing/img/ScaleType.java index c1e96cf5f..1d6881a65 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/ScaleType.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/img/ScaleType.java @@ -1,4 +1,4 @@ -package cn.hutool.core.img; +package cn.hutool.swing.img; import java.awt.Image; @@ -10,15 +10,25 @@ import java.awt.Image; */ public enum ScaleType { - /** 默认 */ + /** + * 默认 + */ DEFAULT(Image.SCALE_DEFAULT), - /** 快速 */ + /** + * 快速 + */ FAST(Image.SCALE_FAST), - /** 平滑 */ + /** + * 平滑 + */ SMOOTH(Image.SCALE_SMOOTH), - /** 使用 ReplicateScaleFilter 类中包含的图像缩放算法 */ + /** + * 使用 ReplicateScaleFilter 类中包含的图像缩放算法 + */ REPLICATE(Image.SCALE_REPLICATE), - /** Area Averaging算法 */ + /** + * Area Averaging算法 + */ AREA_AVERAGING(Image.SCALE_AREA_AVERAGING); /** @@ -37,6 +47,11 @@ public enum ScaleType { private final int value; + /** + * 获取值 + * + * @return 值 + */ public int getValue() { return this.value; } diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/AnimatedGifEncoder.java b/hutool-swing/src/main/java/cn/hutool/swing/img/gif/AnimatedGifEncoder.java index 2f54aa7c1..52d6c2ca6 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/gif/AnimatedGifEncoder.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/img/gif/AnimatedGifEncoder.java @@ -296,6 +296,7 @@ public class AnimatedGifEncoder { public boolean start(final String file) { boolean ok; try { + //noinspection IOStreamConstructor out = new BufferedOutputStream(new FileOutputStream(file)); ok = start(out); closeStream = true; @@ -305,6 +306,9 @@ public class AnimatedGifEncoder { return started = ok; } + /** + * @return 是否开始 + */ public boolean isStarted() { return started; } @@ -339,7 +343,7 @@ public class AnimatedGifEncoder { pixels = null; colorDepth = 8; palSize = 7; - // get closest match to transparent color if specified + // get the closest match to transparent color if specified if (transparent != null) { transIndex = transparentExactMatch ? findExact(transparent) : findClosest(transparent); } @@ -377,7 +381,7 @@ public class AnimatedGifEncoder { /** * Returns true if the exact matching color is existing, and used in the color palette, otherwise, return false. * This method has to be called before finishing the image, - * because after finished the palette is destroyed and it will always return false. + * because after finished the palette is destroyed, and it will always return false. * * @param c 颜色 * @return 颜色是否存在 From 96d6c39a14b801406a8e921c0a02477de327fccc Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 15 Sep 2022 13:21:50 +0800 Subject: [PATCH 30/73] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=8F=AF=E9=87=8D=E5=A4=8D=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotation/AnnotatedElementUtil.java | 199 +++++++- .../core/annotation/AnnotationUtil.java | 34 +- .../CombinationAnnotationElement.java | 10 +- .../HierarchicalAnnotatedElements.java | 2 +- .../core/annotation/MetaAnnotatedElement.java | 68 +-- .../RepeatableAnnotationCollector.java | 449 ++++++++++++++++++ .../RepeatableMetaAnnotatedElement.java | 387 +++++++++++++++ .../annotation/ResolvedAnnotationMapping.java | 9 +- .../annotation/AnnotatedElementUtilTest.java | 155 ++++++ .../core/annotation/AnnotationUtilTest.java | 24 + .../annotation/MetaAnnotatedElementTest.java | 7 + .../RepeatableAnnotationCollectorTest.java | 220 +++++++++ .../RepeatableMetaAnnotatedElementTest.java | 212 +++++++++ 13 files changed, 1716 insertions(+), 60 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java index 2407de316..62c81f338 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java @@ -93,11 +93,35 @@ import java.util.stream.Stream; * * * + *

    可重复注解支持 + *

    工具类中格式为findAllXXXgetAllXXX格式的方法, + * 支持获得{@link AnnotatedElement}上的可重复注解。 + * 此处的可重复注解定义包括两方面: + *

      + *
    • + * 若{@link AnnotatedElement}存在直接声明的注解,该注解有且仅有一个value属性, + * 该属性类型为注解数组,且数组中注解被{@link java.lang.annotation.Repeatable}注解, + * 则认为被包括的注解为可重复注解;
      + * eg:
      + * A上存在注解X,该注解是一个容器注解,内部可重复注解Y, + * 包含解析后,得到注解X与它包含的可重复注解Y; + *
    • + *
    • + * 若{@link AnnotatedElement}存在直接声明的注解,该注解与其他根注解皆有相同的元注解, + * 则获得元注解时,可以获得多个该相同的元注解。
      + * eg:
      + * A上存在注解XY,两者皆有元注解Z, + * 则通过{@link AnnotatedElement}可以获得两个Z + *
    • + *
    + * * @author huangchengxing * @see ResolvedAnnotationMapping * @see GenericAnnotationMapping * @see HierarchicalAnnotatedElements + * @see RepeatableMetaAnnotatedElement * @see MetaAnnotatedElement + * @see RepeatableAnnotationCollector * @since 6.0.0 */ public class AnnotatedElementUtil { @@ -112,6 +136,16 @@ public class AnnotatedElementUtil { */ private static final Map> ELEMENT_CACHE = new WeakConcurrentMap<>(); + /** + * 不支持属性解析的{@link RepeatableMetaAnnotatedElement}缓存 + */ + private static final Map> RESOLVED_REPEATABLE_ELEMENT_CACHE = new WeakConcurrentMap<>(); + + /** + * 不支持属性解析的{@link RepeatableMetaAnnotatedElement}缓存 + */ + private static final Map> REPEATABLE_ELEMENT_CACHE = new WeakConcurrentMap<>(); + // region ========== find ========== /** @@ -140,7 +174,8 @@ public class AnnotatedElementUtil { } /** - * 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取所有该类型的注解或元注解 + * 从{@code element}所处层级结构的所有{@link AnnotatedElement}上直接声明的注解、 + * 这些注解包含的可重复注解,以及上述所有注解的元注解中获取指定类型注解 * * @param element {@link AnnotatedElement} * @param annotationType 注解类型 @@ -148,7 +183,7 @@ public class AnnotatedElementUtil { * @return 注解对象 */ public static T[] findAllAnnotations(final AnnotatedElement element, final Class annotationType) { - return toHierarchyMetaElement(element, false) + return toHierarchyRepeatableMetaElement(element, false) .getAnnotationsByType(annotationType); } @@ -190,7 +225,8 @@ public class AnnotatedElementUtil { } /** - * 从{@code element}所处层级结构的所有{@link AnnotatedElement}上,获取所有该类型的注解或元注解。
    + * 从{@code element}所处层级结构的所有{@link AnnotatedElement}上直接声明的注解、 + * 这些注解包含的可重复注解,以及上述所有注解的元注解中获取指定类型注解。
    * 得到的注解支持基于{@link Alias}的别名、及子注解对元注解中同名同类型属性进行覆写的特殊机制。 * * @param element {@link AnnotatedElement} @@ -199,7 +235,7 @@ public class AnnotatedElementUtil { * @return 注解对象 */ public static T[] findAllResolvedAnnotations(final AnnotatedElement element, final Class annotationType) { - return toHierarchyMetaElement(element, true) + return toHierarchyRepeatableMetaElement(element, true) .getAnnotationsByType(annotationType); } @@ -221,7 +257,8 @@ public class AnnotatedElementUtil { } /** - * 从{@code element}所处层级结构的所有{@link AnnotatedElement}上获取所有该类型的注解 + * 从{@code element}上直接声明的注解、这些注解包含的可重复注解, + * 以及上述所有注解的元注解中获取指定类型注解。 * * @param element {@link AnnotatedElement} * @param annotationType 注解类型 @@ -229,7 +266,7 @@ public class AnnotatedElementUtil { * @return 注解对象 */ public static T[] findAllDirectlyAnnotations(final AnnotatedElement element, final Class annotationType) { - return toHierarchyMetaElement(element, false) + return toHierarchyRepeatableMetaElement(element, false) .getDeclaredAnnotationsByType(annotationType); } @@ -271,7 +308,8 @@ public class AnnotatedElementUtil { } /** - * 从{@code element}所处层级结构的所有{@link AnnotatedElement}上获取所有该类型的注解。
    + * 从{@code element}所处层级结构的所有{@link AnnotatedElement}上直接声明的注解、 + * 这些注解包含的可重复注解,以及上述所有注解的元注解中获取指定类型注解。
    * 得到的注解支持基于{@link Alias}的别名、及子注解对元注解中同名同类型属性进行覆写的特殊机制。 * * @param element {@link AnnotatedElement} @@ -280,7 +318,7 @@ public class AnnotatedElementUtil { * @return 注解对象 */ public static T[] findAllDirectlyResolvedAnnotations(final AnnotatedElement element, final Class annotationType) { - return toHierarchyMetaElement(element, true) + return toHierarchyRepeatableMetaElement(element, true) .getDeclaredAnnotationsByType(annotationType); } @@ -324,6 +362,19 @@ public class AnnotatedElementUtil { .getAnnotations(); } + /** + * 从{@code element}上直接声明的注解、这些注解包含的可重复注解,以及上述所有注解的元注解中获取指定类型注解 + * + * @param element {@link AnnotatedElement} + * @param annotationType 注解类型 + * @param 注解类型 + * @return 注解对象 + */ + public static T[] getAllAnnotations(final AnnotatedElement element, final Class annotationType) { + return toRepeatableMetaElement(element, false) + .getAnnotationsByType(annotationType); + } + /** * 从{@code element}上,获取所有的注解或元注解。
    * 得到的注解支持基于{@link Alias}的别名机制。 @@ -350,6 +401,20 @@ public class AnnotatedElementUtil { .getAnnotations(); } + /** + * 从{@code element}上直接声明的注解、这些注解包含的可重复注解,以及上述所有注解的元注解中获取指定类型注解
    + * 得到的注解支持基于{@link Alias}的别名机制。 + * + * @param element {@link AnnotatedElement} + * @param annotationType 注解类型 + * @param 注解类型 + * @return 注解对象 + */ + public static T[] getAllResolvedAnnotations(final AnnotatedElement element, final Class annotationType) { + return toRepeatableMetaElement(element, true) + .getAnnotationsByType(annotationType); + } + // endregion // region ========== get & direct ========== @@ -367,6 +432,19 @@ public class AnnotatedElementUtil { .getDeclaredAnnotation(annotationType); } + /** + * 从{@code element}上直接声明的注解、这些注解包含的可重复注解中获取指定类型注解 + * + * @param element {@link AnnotatedElement} + * @param annotationType 注解类型 + * @param 注解类型 + * @return 注解对象 + */ + public static T[] getAllDirectlyAnnotations(final AnnotatedElement element, final Class annotationType) { + return toRepeatableMetaElement(element, false) + .getDeclaredAnnotationsByType(annotationType); + } + /** * 从{@code element}上获取所有的注解 * @@ -404,6 +482,19 @@ public class AnnotatedElementUtil { .getDeclaredAnnotations(); } + /** + * 从{@code element}上直接声明的注解、这些注解包含的可重复注解中获取指定类型注解 + * + * @param element {@link AnnotatedElement} + * @param annotationType 注解类型 + * @param 注解类型 + * @return 注解对象 + */ + public static T[] getAllDirectlyResolvedAnnotations(final AnnotatedElement element, final Class annotationType) { + return toRepeatableMetaElement(element, true) + .getDeclaredAnnotationsByType(annotationType); + } + // endregion // region ========== to element ========== @@ -430,6 +521,29 @@ public class AnnotatedElementUtil { return HierarchicalAnnotatedElements.create(element, (es, e) -> getMetaElementCache(e)); } + /** + *

    扫描{@code element}所处层级结构中的{@link AnnotatedElement}, + * 并将其全部转为{@link RepeatableMetaAnnotatedElement}后, + * 再把所有对象合并为{@link HierarchicalAnnotatedElements}。
    + * 得到的对象可访问{@code element}所处层级结构中所有{@link AnnotatedElement}上的直接声明的注解, + * 这些注解包含的可重复注解,以及上述注解的所有元注解。 + * + * @param element 元素 + * @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制 + * @return {@link HierarchicalAnnotatedElements}实例 + * @see #getRepeatableMetaElementCache(AnnotatedElement) + * @see #getResolvedRepeatableMetaElementCache(AnnotatedElement) + */ + public static AnnotatedElement toHierarchyRepeatableMetaElement(final AnnotatedElement element, final boolean resolved) { + if (Objects.isNull(element)) { + return emptyElement(); + } + if (resolved) { + return HierarchicalAnnotatedElements.create(element, (es, e) -> getResolvedRepeatableMetaElementCache(e)); + } + return HierarchicalAnnotatedElements.create(element, (es, e) -> getRepeatableMetaElementCache(e)); + } + /** *

    扫描{@code element}所处层级结构中的{@link AnnotatedElement}, * 再把所有对象合并为{@link HierarchicalAnnotatedElements} @@ -460,6 +574,49 @@ public class AnnotatedElementUtil { ); } + /** + * 将{@link AnnotatedElement}转为{@link RepeatableMetaAnnotatedElement}, + * 得到的对象可访问{@link AnnotatedElement}上的直接声明的注解,这些注解包含的可重复注解,以及上述注解的所有元注解。 + * + * @param element 元素 + * @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制 + * @return {@link AnnotatedElement}实例 + * @see #getMetaElementCache(AnnotatedElement) + * @see #getResolvedMetaElementCache(AnnotatedElement) + */ + public static AnnotatedElement toRepeatableMetaElement(final AnnotatedElement element, final boolean resolved) { + return ObjUtil.defaultIfNull( + element, e -> resolved ? getResolvedRepeatableMetaElementCache(e) : getRepeatableMetaElementCache(e), emptyElement() + ); + } + + /** + *

    将{@link AnnotatedElement}转为{@link RepeatableMetaAnnotatedElement}, + * 得到的对象可访问{@link AnnotatedElement}上的直接声明的注解, + * 通过{@code collector}从这些注解获得的可重复注解,以及上述注解的所有元注解。
    + * 注意:方法将不会通过缓存结果,因此每次调用都需要重新通过反射并获得相关注解。 + * + * @param collector 可重复注解收集器,为{@code null}时等同于{@link RepeatableAnnotationCollector#none()} + * @param element 元素 + * @param resolved 是否解析注解属性,若为{@code true}则获得的注解将支持属性别名以及属性覆盖机制 + * @return {@link AnnotatedElement}实例 + */ + public static AnnotatedElement toRepeatableMetaElement( + final AnnotatedElement element, RepeatableAnnotationCollector collector, final boolean resolved) { + if (Objects.isNull(element)) { + return emptyElement(); + } + collector = ObjUtil.defaultIfNull(collector, RepeatableAnnotationCollector.none()); + if (resolved) { + return RepeatableMetaAnnotatedElement.create( + collector, element, (source, annotation) -> ResolvedAnnotationMapping.create((ResolvedAnnotationMapping)source, annotation, true) + ); + } + return RepeatableMetaAnnotatedElement.create( + collector, element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source)) + ); + } + /** * 将一组注解中的非{@code null}注解对象合并为一个{@link AnnotatedElement} * @@ -500,7 +657,7 @@ public class AnnotatedElementUtil { } /** - * 创建一个支持注解解析的{@link MetaAnnotatedElement} + * 创建一个不支持注解解析的{@link MetaAnnotatedElement} * * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 @@ -511,6 +668,30 @@ public class AnnotatedElementUtil { )); } + /** + * 创建一个支持注解解析的{@link RepeatableMetaAnnotatedElement} + * + * @param element {@link AnnotatedElement} + * @return {@link MetaAnnotatedElement}实例 + */ + private static RepeatableMetaAnnotatedElement getResolvedRepeatableMetaElementCache(final AnnotatedElement element) { + return RESOLVED_REPEATABLE_ELEMENT_CACHE.computeIfAbsent(element, ele -> RepeatableMetaAnnotatedElement.create( + element, (source, annotation) -> ResolvedAnnotationMapping.create(source, annotation, true) + )); + } + + /** + * 创建一个不支持注解解析的{@link RepeatableMetaAnnotatedElement} + * + * @param element {@link AnnotatedElement} + * @return {@link MetaAnnotatedElement}实例 + */ + private static RepeatableMetaAnnotatedElement getRepeatableMetaElementCache(final AnnotatedElement element) { + return REPEATABLE_ELEMENT_CACHE.computeIfAbsent(element, ele -> RepeatableMetaAnnotatedElement.create( + element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source)) + )); + } + // endregion /** diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index 124ac5eac..eca5f86b5 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -1,6 +1,8 @@ package cn.hutool.core.annotation; import cn.hutool.core.exceptions.UtilException; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.reflect.FieldUtil; import cn.hutool.core.reflect.MethodUtil; import cn.hutool.core.util.ArrayUtil; @@ -13,7 +15,6 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Stream; @@ -26,6 +27,27 @@ import java.util.stream.Stream; */ public class AnnotationUtil { + /** + * 注解属性缓存 + */ + private static final Map, Method[]> ANNOTATION_ATTRIBUTES_CACHE = new WeakConcurrentMap<>(); + + /** + * 直接声明的注解缓存 + */ + private static final Map DECLARED_ANNOTATIONS_CACHE = new WeakConcurrentMap<>(); + + /** + * 获取直接声明的注解,若已有缓存则从缓存中获取 + * + * @param element {@link AnnotatedElement} + * @return 注解 + * @since 6.0.0 + */ + public static Annotation[] getDeclaredAnnotations(AnnotatedElement element) { + return MapUtil.computeIfAbsent(DECLARED_ANNOTATIONS_CACHE, element, AnnotatedElement::getDeclaredAnnotations); + } + /** * 将指定的被注解的元素转换为组合注解元素 * @@ -295,18 +317,18 @@ public class AnnotationUtil { } /** - * 获取注解属性 + * 获取注解属性,若已有缓存则从缓存中获取 * * @param annotationType 注解类型 * @return 注解属性 * @since 6.0.0 */ public static Method[] getAnnotationAttributes(final Class annotationType) { - // TODO 改为通过带缓存的反射工具类完成 - Objects.requireNonNull(annotationType); - return Stream.of(annotationType.getDeclaredMethods()) + return MapUtil.computeIfAbsent( + ANNOTATION_ATTRIBUTES_CACHE, annotationType, type -> Stream.of(annotationType.getDeclaredMethods()) .filter(AnnotationUtil::isAnnotationAttribute) - .toArray(Method[]::new); + .toArray(Method[]::new) + ); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java index abbca341b..adbce12c3 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java @@ -4,11 +4,7 @@ import cn.hutool.core.collection.SetUtil; import cn.hutool.core.map.TableMap; import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.lang.annotation.Documented; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; +import java.lang.annotation.*; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.Collection; @@ -115,7 +111,7 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa * @param element 元素 */ private void init(final AnnotatedElement element) { - final Annotation[] declaredAnnotations = element.getDeclaredAnnotations(); + final Annotation[] declaredAnnotations = AnnotationUtil.getDeclaredAnnotations(element); this.declaredAnnotationMap = new TableMap<>(); parseDeclared(declaredAnnotations); @@ -145,7 +141,7 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa declaredAnnotationMap.put(annotationType, annotation); } // 测试不通过的注解,不影响继续递归 - parseDeclared(annotationType.getDeclaredAnnotations()); + parseDeclared(AnnotationUtil.getDeclaredAnnotations(annotationType)); } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java b/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java index a6f06ad8e..152154b56 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java @@ -172,7 +172,7 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable @Override public Annotation[] getDeclaredAnnotations() { return getElementMappings().stream() - .map(AnnotatedElement::getDeclaredAnnotations) + .map(AnnotationUtil::getDeclaredAnnotations) .filter(ArrayUtil::isNotEmpty) .flatMap(Stream::of) .toArray(Annotation[]::new); diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/MetaAnnotatedElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/MetaAnnotatedElement.java index 26e0567cc..313642514 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/MetaAnnotatedElement.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/MetaAnnotatedElement.java @@ -21,8 +21,11 @@ import java.util.stream.Stream; * 并且在当前实例中,{@link Inherited}注解将不生效, * 即通过directly方法将无法获得父类上带有{@link Inherited}的注解。 * - *

    当通过静态工厂方法创建时,该实例与关联的{@link ResolvedAnnotationMapping}都会针对{@link ResolvedAnnotationMapping}进行缓存, - * 从而避免频繁的反射与代理造成不必要的性能损耗。 + *

    在一个{@link MetaAnnotatedElement}中, + * {@link AnnotatedElement}上同类型的注解或元注解只会被保留一个, + * 即当出现两个根注解都具有相同元注解时,仅有第一个根注解上的元注解会被保留, + * 因此当通过{@link #getAnnotationsByType(Class)} + * 或{@link #getDeclaredAnnotationsByType(Class)}方法用于只能获得一个注解对象。 * * @author huangchengxing * @see ResolvedAnnotationMapping @@ -214,6 +217,34 @@ public class MetaAnnotatedElement> imple return getAnnotationMappings().values().iterator(); } + /** + * 比较两个实例是否相等 + * + * @param o 对象 + * @return 是否 + */ + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final MetaAnnotatedElement that = (MetaAnnotatedElement)o; + return element.equals(that.element) && mappingFactory.equals(that.mappingFactory); + } + + /** + * 获取实例的哈希值 + * + * @return 哈希值 + */ + @Override + public int hashCode() { + return Objects.hash(element, mappingFactory); + } + // ========================= protected ========================= /** @@ -270,7 +301,7 @@ public class MetaAnnotatedElement> imple */ private void initAnnotationMappings(final Map, T> mappings) { final Deque deque = new LinkedList<>(); - Arrays.stream(element.getDeclaredAnnotations()) + Arrays.stream(AnnotationUtil.getDeclaredAnnotations(element)) .filter(m -> isNeedMapping(mappings, m)) .map(annotation -> createMapping(null, annotation)) .filter(Objects::nonNull) @@ -283,40 +314,11 @@ public class MetaAnnotatedElement> imple } // 保存该注解,并将其需要处理的元注解也加入队列 mappings.put(mapping.annotationType(), mapping); - Stream.of(mapping.annotationType().getDeclaredAnnotations()) + Stream.of(AnnotationUtil.getDeclaredAnnotations(mapping.annotationType())) .map(annotation -> createMapping(mapping, annotation)) .filter(Objects::nonNull) .filter(m -> isNeedMapping(mappings, m)) .forEach(deque::addLast); } } - - /** - * 比较两个实例是否相等 - * - * @param o 对象 - * @return 是否 - */ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MetaAnnotatedElement that = (MetaAnnotatedElement)o; - return element.equals(that.element) && mappingFactory.equals(that.mappingFactory); - } - - /** - * 获取实例的哈希值 - * - * @return 哈希值 - */ - - @Override - public int hashCode() { - return Objects.hash(element, mappingFactory); - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java new file mode 100644 index 000000000..38579178d --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java @@ -0,0 +1,449 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.map.WeakConcurrentMap; +import cn.hutool.core.reflect.MethodUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ArrayUtil; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Repeatable; +import java.lang.reflect.Method; +import java.util.*; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 可重复注解收集器,用于从一个注解获得被它包含的可重复注解 + * + * @author huangchengxing + */ +public interface RepeatableAnnotationCollector { + + /** + * 空实现 + * + * @return {@link RepeatableAnnotationCollector}实例 + */ + static RepeatableAnnotationCollector none() { + return None.INSTANCE; + } + + /** + * 当注解中有且仅有一个名为{@code value}的属性时, + * 若该属性类型为注解数组,且该数组对应的注解类型被{@link Repeatable}注解, + * 则收集器将返回该属性中包括的可重复注解。 + * + * @return {@link RepeatableAnnotationCollector}实例 + * @see Standard + */ + static RepeatableAnnotationCollector standard() { + return Standard.INSTANCE; + } + + /** + * 当解析注解属性时,将根据给定的判断条件,确定该属性中是否含有可重复注解。
    + * 收集器将返回所有匹配的属性中的可重复注解。 + * + * @param predicate 是否为容纳可重复注解的属性的判断条件 + * @return {@link RepeatableAnnotationCollector}实例 + */ + static RepeatableAnnotationCollector condition(final BiPredicate predicate) { + return new Condition(predicate); + } + + /** + * 当注解中存在有属性为注解数组,且该数组对应的注解类型被{@link Repeatable}注解时, + * 认为该属性包含可重复注解。
    + * 收集器将返回所有符合上述条件的属性中的可重复注解。 + * + * @return {@link RepeatableAnnotationCollector}实例 + */ + static RepeatableAnnotationCollector full() { + return Full.INSTANCE; + } + + /** + *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 + * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。 + * + * @param annotation 容器注解 + * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象 + */ + List getRepeatableAnnotations(final Annotation annotation); + + /** + *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 + * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
    + * 当{@code accumulate}为{@code true}时,返回结果为全量的注解。 + * + * @param annotation 容器注解 + * @param accumulate 是否累加 + * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象 + */ + List getRepeatableAnnotations(final Annotation annotation, final boolean accumulate); + + /** + * 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的指定类型注解对象 + * + * @param annotation 容器注解 + * @param annotationType 注解类型 + * @param 注解类型 + * @return 容器注解中的可重复注解 + */ + List getRepeatableAnnotations(final Annotation annotation, final Class annotationType); + + /** + * 空实现 + */ + class None implements RepeatableAnnotationCollector { + + /** + * 默认实例 + */ + private static final None INSTANCE = new None(); + + /** + * 默认返回空集合 + * + * @param annotation 注解 + * @return 空集合 + */ + @Override + public List getRepeatableAnnotations(final Annotation annotation) { + return Objects.isNull(annotation) ? + Collections.emptyList() : Collections.singletonList(annotation); + } + + /** + * 默认返回空集合 + * + * @param annotation 注解 + * @return 空集合 + */ + @Override + public List getRepeatableAnnotations(final Annotation annotation, final boolean accumulate) { + return Objects.isNull(annotation) ? + Collections.emptyList() : Collections.singletonList(annotation); + } + + /** + * 默认返回空集合 + * + * @param annotation 注解 + * @return 空集合 + */ + @Override + public List getRepeatableAnnotations(final Annotation annotation, final Class annotationType) { + if (Objects.isNull(annotation)) { + return Collections.emptyList(); + } + return Objects.equals(annotation.annotationType(), annotationType) ? + Collections.singletonList(annotationType.cast(annotation)) : Collections.emptyList(); + } + + } + + /** + * {@link RepeatableAnnotationCollector}的基本实现 + */ + abstract class AbstractCollector implements RepeatableAnnotationCollector { + + /** + *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 + * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。 + * + * @param annotation 容器注解 + * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象 + */ + @Override + public final List getRepeatableAnnotations(final Annotation annotation) { + return getRepeatableAnnotations(annotation, false); + } + + /** + *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 + * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
    + * 当{@code accumulate}为{@code true}时,返回结果为全量的注解。 + * + * @param annotation 容器注解 + * @param accumulate 是否累加 + * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象 + */ + @Override + public final List getRepeatableAnnotations(final Annotation annotation, final boolean accumulate) { + return find(annotation, null, accumulate); + } + + /** + * 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的指定类型注解对象 + * + * @param annotation 容器注解 + * @param annotationType 注解类型 + * @param 注解类型 + * @return 容器注解中的可重复注解 + */ + @Override + public List getRepeatableAnnotations( + final Annotation annotation, final Class annotationType) { + final List annotations = find(annotation, t -> Objects.equals(t.annotationType(), annotationType), false); + return annotations.stream() + .map(annotationType::cast) + .collect(Collectors.toList()); + } + + /** + * 递归遍历注解,将其平铺 + */ + private List find( + final Annotation annotation, final java.util.function.Predicate condition, final boolean accumulate) { + if (Objects.isNull(annotation)) { + return Collections.emptyList(); + } + final boolean hasCondition = Objects.nonNull(condition); + final List results = new ArrayList<>(); + final Deque deque = new LinkedList<>(); + deque.add(annotation); + while (!deque.isEmpty()) { + final Annotation source = deque.removeFirst(); + final List repeatableMethods = resolveRepeatableMethod(source); + // 若是累加的,则记录每一个注解 + if (accumulate) { + results.add(source); + } + final boolean isTarget = hasCondition && condition.test(source); + if (CollUtil.isEmpty(repeatableMethods) || isTarget) { + // 不是累加的,则仅当正在处理的注解不为可重复注解时才记录 + boolean shouldProcess = !accumulate && (!hasCondition || isTarget); + if (shouldProcess) { + results.add(source); + } + continue; + } + final Annotation[] repeatableAnnotation = repeatableMethods.stream() + .map(method -> getRepeatableAnnotationsFormAttribute(source, method)) + .filter(ArrayUtil::isNotEmpty) + .flatMap(Stream::of) + .toArray(Annotation[]::new); + if (ArrayUtil.isNotEmpty(repeatableAnnotation)) { + CollUtil.addAll(deque, repeatableAnnotation); + } + } + return results; + } + + /** + * 调用{@code value}方法,获得嵌套的可重复注解 + * + * @param annotation 注解对象 + * @param method 容纳可重复注解的方法 + * @return 可重复注解 + * @throws ClassCastException 当{@code method}调用结果无法正确转为{@link Annotation[]}类型时抛出 + */ + protected Annotation[] getRepeatableAnnotationsFormAttribute(final Annotation annotation, final Method method) { + return MethodUtil.invoke(annotation, method); + } + + /** + * 解析获得注解中存放可重复注解的属性 + * + * @param annotation 注解 + * @return 属性 + */ + protected abstract List resolveRepeatableMethod(final Annotation annotation); + + } + + /** + * 标准实现,当注解中有且仅有一个名为{@code value}的属性时, + * 若该属性类型为注解数组,且该数组对应的注解类型被{@link Repeatable}注解, + * 则收集器将返回该属性中包括的可重复注解。 + */ + class Standard extends AbstractCollector { + + /** + * 默认的value属性 + */ + private static final String VALUE = "value"; + + /** + * 默认实例 + */ + private static final Standard INSTANCE = new Standard(); + + /** + * 空方法缓存 + */ + private static final Object NONE = new Object(); + + /** + * 可重复注解对应的方法缓存 + */ + private final Map, Object> repeatableMethodCache = new WeakConcurrentMap<>(); + + /** + * 构造 + */ + Standard() { + } + + /** + * 解析获得注解中存放可重复注解的属性 + * + * @param annotation 注解 + * @return 属性 + */ + @Override + protected List resolveRepeatableMethod(final Annotation annotation) { + final Object cache = MapUtil.computeIfAbsent( + repeatableMethodCache, annotation.annotationType(), this::resolveRepeatableMethodFromType + ); + return (cache == NONE) ? null : Collections.singletonList((Method)cache); + } + + /** + * 从缓存中获得存放可重复注解的属性 + */ + private Object resolveRepeatableMethodFromType(final Class annotationType) { + final Method[] attributes = AnnotationUtil.getAnnotationAttributes(annotationType); + if (attributes.length != 1) { + return NONE; + } + return isRepeatableMethod(attributes[0]) ? attributes[0] : NONE; + } + + /** + * 判断方法是否为容器注解的{@code value}方法 + * + * @param attribute 注解的属性 + * @return 该属性是否为注解存放可重复注解的方法 + */ + protected boolean isRepeatableMethod(final Method attribute) { + // 属性名需为“value” + if (!CharSequenceUtil.equals(VALUE, attribute.getName())) { + return false; + } + final Class attributeType = attribute.getReturnType(); + // 返回值类型需为数组 + return attributeType.isArray() + // 且数组元素需为注解 + && attributeType.getComponentType() + .isAnnotation() + // 该注解类必须被@Repeatable注解,但不要求与当前属性的声明方法一致 + && attributeType.getComponentType() + .isAnnotationPresent(Repeatable.class); + } + + } + + /** + * 自定义判断条件的实现,当解析注解属性时,将根据给定的判断条件, + * 确定该属性中是否含有可重复注解,收集器将返回所有匹配的属性中的可重复注解。 + */ + class Condition extends AbstractCollector { + + /** + * 是否为容纳可重复注解的属性的判断条件 + */ + private final BiPredicate predicate; + + /** + * 构造 + * + * @param predicate 是否为容纳可重复注解的属性的判断条件 + */ + Condition(final BiPredicate predicate) { + this.predicate = Objects.requireNonNull(predicate); + } + + /** + * 解析获得注解中存放可重复注解的属性 + * + * @param annotation 注解 + * @return 属性 + */ + @Override + protected List resolveRepeatableMethod(final Annotation annotation) { + return Stream.of(AnnotationUtil.getAnnotationAttributes(annotation.annotationType())) + .filter(method -> predicate.test(annotation, method)) + .collect(Collectors.toList()); + } + + } + + /** + * 全量实现,当注解中存在有属性为注解数组,且该数组对应的注解类型被{@link Repeatable}注解时, + * 认为该属性包含可重复注解。
    + * 收集器将返回所有符合上述条件的属性中的可重复注解。 + */ + class Full extends AbstractCollector { + + /** + * 默认实例 + */ + private static final Full INSTANCE = new Full(); + + /** + * 空方法缓存 + */ + private static final Object NONE = new Object(); + + /** + * 可重复注解对应的方法缓存 + */ + private final Map, Object> repeatableMethodCache = new WeakConcurrentMap<>(); + + /** + * 构造 + */ + Full() { + } + + /** + * 解析获得注解中存放可重复注解的属性 + * + * @param annotation 注解 + * @return 属性 + */ + @SuppressWarnings("unchecked") + @Override + protected List resolveRepeatableMethod(final Annotation annotation) { + final Object cache = MapUtil.computeIfAbsent( + repeatableMethodCache, annotation.annotationType(), this::resolveRepeatableMethodFromType + ); + return (cache == NONE) ? null : (List)cache; + } + + /** + * 从缓存中获得存放可重复注解的属性 + */ + private Object resolveRepeatableMethodFromType(final Class annotationType) { + final List methods = Stream.of(AnnotationUtil.getAnnotationAttributes(annotationType)) + .filter(this::isRepeatableMethod) + .collect(Collectors.toList()); + return methods.isEmpty() ? NONE : methods; + } + + /** + * 判断方法是否为容器注解的{@code value}方法 + * + * @param attribute 注解的属性 + * @return 该属性是否为注解存放可重复注解的方法 + */ + protected boolean isRepeatableMethod(final Method attribute) { + final Class attributeType = attribute.getReturnType(); + // 返回值类型需为数组 + return attributeType.isArray() + // 且数组元素需为注解 + && attributeType.getComponentType() + .isAnnotation() + // 该注解类必须被@Repeatable注解,但不要求与当前属性的声明方法一致 + && attributeType.getComponentType() + .isAnnotationPresent(Repeatable.class); + } + + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java new file mode 100644 index 000000000..bca63a030 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java @@ -0,0 +1,387 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ArrayUtil; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Repeatable; +import java.lang.reflect.AnnotatedElement; +import java.util.*; +import java.util.function.BiFunction; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + *

    支持可重复注解的增强{@link AnnotatedElement}, + * 功能与{@link MetaAnnotatedElement}类似,但是存在下述差异: + *

      + *
    • + * 限制以同一根注解延伸出的树结构上——而不是{@link AnnotatedElement}上——每种类型注解只能保留一个, + * 即当{@link AnnotatedElement}存在多个根注解有相同的元注解时,这些元注解会都会被扫描到; + *
    • + *
    • + * 支持扫描{@link AnnotatedElement}可重复注解,即当{@link AnnotatedElement}上直接声明的注解 + * 有且仅有一个类型为注解数组的{@code value}属性,且数组中注解类上存在{@link Repeatable}, + * 则认为该注解为容器注解,将会自动将其展开直到不为容器注解为止。
      + * eg:
      + * A上存在注解X,该注解是一个容器注解,内部可重复注解Y, + * 包含解析后,得到注解X与可重复注解Y,
      + * 同理,若存在XYX的嵌套关系,则解析后获得全部三者; + *
    • + *
    + * 由于上述机制,当通过实例的{@link #getAnnotation(Class)}或{@link #getDeclaredAnnotation(Class)} + * 方法获得指定类型注解时,若该类型注解存在多个,仅能尽可能获得最先被扫描到的那一个。 + * + * @author huangchengxing + * @since 6.0.0 + * @see RepeatableAnnotationCollector + */ +public class RepeatableMetaAnnotatedElement> implements AnnotatedElement, Iterable { + + /** + * 包装的{@link AnnotatedElement}对象 + */ + private final AnnotatedElement element; + + /** + * 创建{@link AnnotationMapping}的工厂方法 + */ + private final BiFunction mappingFactory; + + /** + * 解析得到的根注解与元注解的聚合体 + */ + private final List aggregations; + + /** + * 可重复注解收集器 + */ + private final RepeatableAnnotationCollector repeatableCollector; + + /** + * 获取{@link AnnotatedElement}上的注解结构,该方法会针对相同的{@link AnnotatedElement}缓存映射对象 + * + * @param element 被注解元素 + * @param mappingFactory 创建{@link AnnotationMapping}的工厂方法,返回值为{@code null}时将忽略该注解 + * @param {@link AnnotationMapping}类型 + * @return {@link AnnotatedElement}上的注解结构 + */ + public static > RepeatableMetaAnnotatedElement create( + final AnnotatedElement element, final BiFunction mappingFactory) { + return create(RepeatableAnnotationCollector.standard(), element, mappingFactory); + } + + /** + * 获取{@link AnnotatedElement}上的注解结构,该方法会针对相同的{@link AnnotatedElement}缓存映射对象 + * + * @param collector 可重复注解收集器 + * @param element 被注解元素 + * @param mappingFactory 创建{@link AnnotationMapping}的工厂方法,返回值为{@code null}时将忽略该注解 + * @param {@link AnnotationMapping}类型 + * @return {@link AnnotatedElement}上的注解结构 + */ + public static > RepeatableMetaAnnotatedElement create( + final RepeatableAnnotationCollector collector, + final AnnotatedElement element, + final BiFunction mappingFactory) { + return new RepeatableMetaAnnotatedElement<>(collector, element, mappingFactory); + } + + /** + * 创建一个支持可重复注解的增强{@link AnnotatedElement} + * + * @param element 包装的{@link AnnotatedElement}对象 + * @param mappingFactory 创建{@link AnnotationMapping}的工厂方法 + */ + RepeatableMetaAnnotatedElement( + final RepeatableAnnotationCollector repeatableCollector, final AnnotatedElement element, final BiFunction mappingFactory) { + this.element = Objects.requireNonNull(element); + this.mappingFactory = Objects.requireNonNull(mappingFactory); + this.repeatableCollector = repeatableCollector; + this.aggregations = Collections.unmodifiableList(initAggregations(element)); + } + + /** + * 指定注解是否在{@link #element}上直接声明的注解、直接声明的注解包含的可重复注解, + * 以及他们的元注解中存在 + * + * @param annotationType 注解类型 + * @return 是否 + */ + @Override + public boolean isAnnotationPresent(final Class annotationType) { + return aggregations.stream() + .anyMatch(aggregation -> aggregation.getMappings().containsKey(annotationType)); + } + + /** + * 从{@link #element}上直接声明的注解、直接声明的注解包含的可重复注解,以及它们的元注解中获得指定类型的注解 + * + * @param annotationType 注解类型 + * @param 注解类型 + * @return 注解 + */ + @Override + public A getAnnotation(final Class annotationType) { + return aggregations.stream() + .map(Aggregation::getMappings) + .map(annotations -> annotations.get(annotationType)) + .filter(Objects::nonNull) + .findFirst() + .map(T::getResolvedAnnotation) + .map(annotationType::cast) + .orElse(null); + } + + /** + * 获取{@link #element}上直接声明的注解、直接声明的注解包含的可重复注解,以及它们的元注解 + * + * @return 注解 + */ + @Override + public Annotation[] getAnnotations() { + return aggregations.stream() + .map(aggregation -> aggregation.getMappings().values()) + .flatMap(Collection::stream) + .map(T::getResolvedAnnotation) + .toArray(Annotation[]::new); + } + + /** + * 从{@link #element}上直接声明的注解、直接声明的注解包含的可重复注解,以及它们的元注解中获得指定类型的注解 + * + * @param annotationType 注解类型 + * @param 注解类型 + * @return 注解 + */ + @Override + public A[] getAnnotationsByType(final Class annotationType) { + return aggregations.stream() + .map(aggregation -> aggregation.getMappings().get(annotationType)) + .filter(Objects::nonNull) + .map(T::getResolvedAnnotation) + .map(annotationType::cast) + .toArray(size -> ArrayUtil.newArray(annotationType, size)); + } + + /** + * 获取由{@link #element}直接声明的注解,不包含被直接声明的容器注解包括的可重复注解 + * + * @return 注解 + */ + @Override + public Annotation[] getDeclaredAnnotations() { + return aggregations.stream() + .filter(Aggregation::isDirect) + .map(Aggregation::getRoot) + .map(T::getResolvedAnnotation) + .toArray(Annotation[]::new); + } + + /** + * 获取由{@link #element}直接声明的注解,不包含被直接声明的容器注解包括的可重复注解 + * + * @param annotationType 注解类型 + * @param 注解类型 + * @return 注解 + */ + @Override + public A getDeclaredAnnotation(final Class annotationType) { + return aggregations.stream() + .filter(Aggregation::isDirect) + .map(Aggregation::getRoot) + .filter(annotation -> Objects.equals(annotationType, annotation.annotationType())) + .findFirst() + .map(T::getResolvedAnnotation) + .map(annotationType::cast) + .orElse(null); + } + + /** + * 获取由{@link #element}直接声明的注解,不包含被直接声明的容器注解包括的可重复注解 + * + * @param annotationType 注解类型 + * @param 注解类型 + * @return 注解 + */ + @Override + public A[] getDeclaredAnnotationsByType(final Class annotationType) { + return aggregations.stream() + .filter(Aggregation::isDirect) + .map(Aggregation::getRoot) + .filter(annotation -> Objects.equals(annotationType, annotation.annotationType())) + .map(T::getResolvedAnnotation) + .map(annotationType::cast) + .toArray(size -> ArrayUtil.newArray(annotationType, size)); + } + + /** + * 注解对象 + * + * @return 被包装的原始元素 + */ + public AnnotatedElement getElement() { + return element; + } + + /** + * 比较两个实例是否相等 + * + * @param o 对象 + * @return 是否 + */ + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final RepeatableMetaAnnotatedElement that = (RepeatableMetaAnnotatedElement)o; + return element.equals(that.element) && mappingFactory.equals(that.mappingFactory) && repeatableCollector.equals(that.repeatableCollector); + } + + /** + * 获取实例的哈希值 + * + * @return 哈希值 + */ + @Override + public int hashCode() { + return Objects.hash(element, mappingFactory, repeatableCollector); + } + + /** + * 获取迭代器 + * + * @return 迭代器 + */ + @Override + public Iterator iterator() { + return aggregations.stream() + .map(Aggregation::getMappings) + .map(Map::values) + .flatMap(Collection::stream) + .iterator(); + } + + /** + * 初始化 + */ + private List initAggregations(final AnnotatedElement element) { + // TODO 若有可能,一并支持处理元注解中的可重复注解 + List result = new ArrayList<>(); + for (final Annotation declaredAnnotation : AnnotationUtil.getDeclaredAnnotations(element)) { + List repeatableAnnotations = collectRepeatable(declaredAnnotation); + if (CollUtil.isNotEmpty(repeatableAnnotations)) { + result.addAll(repeatableAnnotations); + } + } + return result; + } + + /** + * 若当前注解是可重复注解的容器,则将其平铺后把可重复注解加入{@link #aggregations} + */ + private List collectRepeatable(final Annotation annotation) { + return repeatableCollector.getRepeatableAnnotations(annotation, true) + .stream() + .map(a -> new Aggregation(a, Objects.equals(a, annotation))) + .collect(Collectors.toList()); + } + + /** + * 由根注解与其元注解构成的注解聚合 + */ + class Aggregation { + + /** + * 根注解 + */ + private final T root; + + /** + * 注解 + */ + private volatile Map, T> mappings; + + /** + * 是否是由{@link #element}直接声明的注解 + */ + private final boolean isDirect; + + /** + * 创建一个合并聚合 + */ + public Aggregation(final Annotation root, final boolean isDirect) { + this.root = mappingFactory.apply(null, root); + this.isDirect = isDirect; + } + + /** + * 获得收集到的注解 + */ + private Map, T> getMappings() { + if (Objects.isNull(mappings)) { + synchronized (this) { + if (Objects.isNull(mappings)) { + mappings = Collections.unmodifiableMap(initMetaAnnotations()); + } + } + } + return mappings; + } + + /** + * 获得注解及其元注解 + */ + private Map, T> initMetaAnnotations() { + final Map, T> collectedMappings = new LinkedHashMap<>(); + final Deque deque = new LinkedList<>(); + deque.add(root); + while (!deque.isEmpty()) { + final T source = deque.removeFirst(); + if (!isNeedMapping(collectedMappings, source)) { + continue; + } + collectedMappings.put(source.annotationType(), source); + Stream.of(AnnotationUtil.getDeclaredAnnotations(source.annotationType())) + .map(annotation -> mappingFactory.apply(source, annotation)) + .filter(Objects::nonNull) + .filter(m -> isNeedMapping(collectedMappings, m)) + .forEach(deque::addLast); + } + return collectedMappings; + } + + /** + * 该注解是否需要映射
    + * 默认情况下,已经处理过、或在{@link java.lang}包下的注解不会被处理 + */ + private boolean isNeedMapping(final Map, T> mappings, final Annotation annotation) { + return !CharSequenceUtil.startWith(annotation.annotationType().getName(), "java.lang.") + && !mappings.containsKey(annotation.annotationType()); + } + + /** + * 根注解是否由{@link #element}直接声明 + * + * @return 是否 + */ + public boolean isDirect() { + return isDirect; + } + + /** + * 获取根注解 + * + * @return 根注解 + */ + public T getRoot() { + return root; + } + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/ResolvedAnnotationMapping.java b/hutool-core/src/main/java/cn/hutool/core/annotation/ResolvedAnnotationMapping.java index 26062a144..943b783cb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/ResolvedAnnotationMapping.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/ResolvedAnnotationMapping.java @@ -170,7 +170,7 @@ public class ResolvedAnnotationMapping implements AnnotationMapping Arrays.fill(this.resolvedAttributes, NOT_FOUND_INDEX); // 若有必要,解析属性 - // TODO 可能的改进:flag改为枚举,使得可以自行选择:1.只支持属性别名,2.只支持属性覆盖,3.两个都支持,4.两个都不支持 + // TODO flag改为枚举,使得可以自行选择:1.只支持属性别名,2.只支持属性覆盖,3.两个都支持,4.两个都不支持 this.resolved = resolveAttribute && resolveAttributes(); } @@ -178,6 +178,7 @@ public class ResolvedAnnotationMapping implements AnnotationMapping * 解析属性 */ private boolean resolveAttributes() { + // TODO 支持处理@PropIgnore,被标记的属性无法被覆写,也不会被别名关联 // 解析同一注解中的别名 resolveAliasAttributes(); // 使用子注解覆写当前注解中的属性 @@ -525,8 +526,8 @@ public class ResolvedAnnotationMapping implements AnnotationMapping // 根据AliasSet更新关联的属性 Stream.of(aliasSets).filter(Objects::nonNull).forEach(set -> { - final int resolvedIndex = set.resolve(); - set.forEach(index -> resolvedAttributes[index] = resolvedIndex); + final int effectiveAttributeIndex = set.determineEffectiveAttribute(); + set.forEach(index -> resolvedAttributes[index] = effectiveAttributeIndex); }); } @@ -616,7 +617,7 @@ public class ResolvedAnnotationMapping implements AnnotationMapping *
  • 若有多个属性具有非默认值,则要求所有的非默认值都必须相等,若符合并返回该首个具有非默认值的属性,否则报错;
  • * */ - private int resolve() { + private int determineEffectiveAttribute() { int resolvedIndex = NOT_FOUND_INDEX; boolean hasNotDef = false; Object lastValue = null; diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java index 03ed704a6..9b2fe5b85 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java @@ -243,6 +243,25 @@ public class AnnotatedElementUtilTest { ); } + @Test + public void testGetAllAnnotations() { + Annotation3[] resolvedAnnotation3s = AnnotatedElementUtil.getAllAnnotations(Foo.class, Annotation3.class); + Assert.assertEquals(1, resolvedAnnotation3s.length); + Assert.assertEquals(ANNOTATION3, resolvedAnnotation3s[0]); // value与alias互为别名 + + Annotation2[] resolvedAnnotation2s = AnnotatedElementUtil.getAllAnnotations(Foo.class, Annotation2.class); + Assert.assertEquals(1, resolvedAnnotation2s.length); + Assert.assertEquals(ANNOTATION2, resolvedAnnotation2s[0]); // value与alias互为别名 + + Annotation1[] resolvedAnnotation1s = AnnotatedElementUtil.getAllAnnotations(Foo.class, Annotation1.class); + Assert.assertEquals(1, resolvedAnnotation1s.length); + Assert.assertEquals(ANNOTATION1, resolvedAnnotation1s[0]); + + Assert.assertEquals(0, AnnotatedElementUtil.getAllAnnotations(Foo.class, Annotation4.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllAnnotations(Foo.class, Annotation5.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllAnnotations(Foo.class, Annotation6.class).length); + } + @Test public void testGetResolvedAnnotation() { Annotation3 resolvedAnnotation3 = AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation3.class); @@ -264,6 +283,33 @@ public class AnnotatedElementUtilTest { Assert.assertNull(AnnotatedElementUtil.getResolvedAnnotation(Foo.class, Annotation6.class)); } + @Test + public void testGetAllResolvedAnnotations() { + Annotation3[] resolvedAnnotation3s = AnnotatedElementUtil.getAllResolvedAnnotations(Foo.class, Annotation3.class); + Assert.assertEquals(1, resolvedAnnotation3s.length); + Annotation3 resolvedAnnotation3 = resolvedAnnotation3s[0]; + Assert.assertNotNull(resolvedAnnotation3); + Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value()); + Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名 + + Annotation2[] resolvedAnnotation2s = AnnotatedElementUtil.getAllResolvedAnnotations(Foo.class, Annotation2.class); + Assert.assertEquals(1, resolvedAnnotation2s.length); + Annotation2 resolvedAnnotation2 = resolvedAnnotation2s[0]; + Assert.assertNotNull(resolvedAnnotation2); + Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖 + + Annotation1[] resolvedAnnotation1s = AnnotatedElementUtil.getAllResolvedAnnotations(Foo.class, Annotation1.class); + Assert.assertEquals(1, resolvedAnnotation1s.length); + Annotation1 resolvedAnnotation1 = resolvedAnnotation1s[0]; + Assert.assertNotNull(resolvedAnnotation1); + Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖 + Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名 + + Assert.assertEquals(0, AnnotatedElementUtil.getAllResolvedAnnotations(Foo.class, Annotation4.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllResolvedAnnotations(Foo.class, Annotation5.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllResolvedAnnotations(Foo.class, Annotation6.class).length); + } + @Test public void testGetResolvedAnnotations() { Map, Annotation> annotationMap = Stream.of(AnnotatedElementUtil.getResolvedAnnotations(Foo.class)) @@ -299,6 +345,20 @@ public class AnnotatedElementUtilTest { Assert.assertNull(AnnotatedElementUtil.getDirectlyAnnotation(Foo.class, Annotation6.class)); } + @Test + public void testGetAllDirectlyAnnotations() { + Annotation3[] resolvedAnnotation3s = AnnotatedElementUtil.getAllDirectlyAnnotations(Foo.class, Annotation3.class); + Assert.assertEquals(1, resolvedAnnotation3s.length); + Annotation3 resolvedAnnotation3 = resolvedAnnotation3s[0]; + Assert.assertEquals(ANNOTATION3, resolvedAnnotation3); + + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation2.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation1.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation4.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation5.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation6.class).length); + } + @Test public void testGetDirectlyAnnotations() { Annotation[] annotations = AnnotatedElementUtil.getDirectlyAnnotations(Foo.class); @@ -320,6 +380,22 @@ public class AnnotatedElementUtilTest { Assert.assertNull(AnnotatedElementUtil.getDirectlyResolvedAnnotation(Foo.class, Annotation6.class)); } + @Test + public void testGetDirectlyAllResolvedAnnotations() { + Annotation3[] resolvedAnnotation3s = AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation3.class); + Assert.assertEquals(1, resolvedAnnotation3s.length); + Annotation3 resolvedAnnotation3 = resolvedAnnotation3s[0]; + Assert.assertNotNull(resolvedAnnotation3); + Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value()); + Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名 + + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation2.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation1.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation4.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation5.class).length); + Assert.assertEquals(0, AnnotatedElementUtil.getAllDirectlyResolvedAnnotations(Foo.class, Annotation6.class).length); + } + @Test public void testGetDirectlyResolvedAnnotations() { Annotation[] annotations = AnnotatedElementUtil.getDirectlyResolvedAnnotations(Foo.class); @@ -364,6 +440,39 @@ public class AnnotatedElementUtilTest { Assert.assertEquals(ANNOTATION5, resolvedElement.getAnnotation(Annotation5.class)); } + @Test + public void testToHierarchyRepeatableMetaElement() { + Assert.assertNotNull(AnnotatedElementUtil.toHierarchyRepeatableMetaElement(null, false)); + Assert.assertNotNull(AnnotatedElementUtil.toHierarchyRepeatableMetaElement(null, true)); + AnnotatedElement element = AnnotatedElementUtil.toHierarchyRepeatableMetaElement(Foo.class, false); + + // 带有元注解 + Assert.assertArrayEquals(ANNOTATIONS, element.getAnnotations()); + + // 不带元注解 + Assert.assertArrayEquals(DECLARED_ANNOTATIONS, element.getDeclaredAnnotations()); + + // 解析注解属性 + AnnotatedElement resolvedElement = AnnotatedElementUtil.toHierarchyRepeatableMetaElement(Foo.class, true); + Annotation3 resolvedAnnotation3 = resolvedElement.getAnnotation(Annotation3.class); + Assert.assertNotNull(resolvedAnnotation3); + Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value()); + Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名 + + Annotation2 resolvedAnnotation2 = resolvedElement.getAnnotation(Annotation2.class); + Assert.assertNotNull(resolvedAnnotation2); + Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖 + + Annotation1 resolvedAnnotation1 = resolvedElement.getAnnotation(Annotation1.class); + Assert.assertNotNull(resolvedAnnotation1); + Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖 + Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名 + + Assert.assertEquals(ANNOTATION4, resolvedElement.getAnnotation(Annotation4.class)); + Assert.assertEquals(ANNOTATION6, resolvedElement.getAnnotation(Annotation6.class)); + Assert.assertEquals(ANNOTATION5, resolvedElement.getAnnotation(Annotation5.class)); + } + @Test public void testToHierarchyElement() { Assert.assertNotNull(AnnotatedElementUtil.toHierarchyElement(Foo.class)); @@ -401,6 +510,36 @@ public class AnnotatedElementUtilTest { Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名 } + @Test + public void testToRepeatableMetaElement() { + Assert.assertNotNull(AnnotatedElementUtil.toRepeatableMetaElement(null, RepeatableAnnotationCollector.none(), false)); + Assert.assertNotNull(AnnotatedElementUtil.toRepeatableMetaElement(null, RepeatableAnnotationCollector.none(), true)); + + // 不解析注解属性 + AnnotatedElement element = AnnotatedElementUtil.toRepeatableMetaElement(Foo.class, RepeatableAnnotationCollector.none(), false); + Assert.assertEquals(element, AnnotatedElementUtil.toRepeatableMetaElement(Foo.class, RepeatableAnnotationCollector.none(), false)); // 第二次获取时从缓存中获取 + Assert.assertArrayEquals(new Annotation[]{ANNOTATION3, ANNOTATION2, ANNOTATION1}, element.getAnnotations()); + + // 解析注解属性 + element = AnnotatedElementUtil.toRepeatableMetaElement(Foo.class, RepeatableAnnotationCollector.none(), true); + Assert.assertEquals(element, AnnotatedElementUtil.toRepeatableMetaElement(Foo.class, RepeatableAnnotationCollector.none(), true)); // 第二次获取时从缓存中获取 + Assert.assertEquals(3, element.getAnnotations().length); + + Annotation3 resolvedAnnotation3 = element.getAnnotation(Annotation3.class); + Assert.assertNotNull(resolvedAnnotation3); + Assert.assertEquals(resolvedAnnotation3.alias(), ANNOTATION3.value()); + Assert.assertEquals(resolvedAnnotation3.alias(), resolvedAnnotation3.value()); // value与alias互为别名 + + Annotation2 resolvedAnnotation2 = element.getAnnotation(Annotation2.class); + Assert.assertNotNull(resolvedAnnotation2); + Assert.assertEquals(resolvedAnnotation2.num(), ANNOTATION3.num()); // num属性被Annotation3.num覆盖 + + Annotation1 resolvedAnnotation1 = element.getAnnotation(Annotation1.class); + Assert.assertNotNull(resolvedAnnotation1); + Assert.assertEquals(ANNOTATION3.value(), resolvedAnnotation1.value()); // value属性被Annotation3.value覆盖 + Assert.assertEquals(resolvedAnnotation1.value(), resolvedAnnotation1.alias()); // value与alias互为别名 + } + @Test public void testAsElement() { Annotation[] annotations = new Annotation[]{ANNOTATION1, ANNOTATION2}; @@ -474,6 +613,22 @@ public class AnnotatedElementUtilTest { int num() default Integer.MIN_VALUE; } + /** + *

    Foo.class上注解情况如下: + *

    {@code
    +	 * annotation3 => annotation2 => annotation1
    +	 * }
    + * + *

    Super.class上注解情况如下: + *

    {@code
    +	 * annotation4
    +	 * }
    + * + *

    Interface.class上注解情况如下: + *

    {@code
    +	 * annotation6 => annotation5 => annotation6【循环引用】
    +	 * }
    + */ @Annotation3(value = "foo", num = Integer.MAX_VALUE) private static class Foo extends Super implements Interface {} diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java index 5d3612bc8..ebd3cdb44 100755 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java @@ -1,10 +1,12 @@ package cn.hutool.core.annotation; import cn.hutool.core.util.ObjUtil; +import lombok.SneakyThrows; import org.junit.Assert; import org.junit.Test; import java.lang.annotation.*; +import java.lang.reflect.Method; import java.util.Map; /** @@ -12,6 +14,13 @@ import java.util.Map; */ public class AnnotationUtilTest { + @Test + public void testGetDeclaredAnnotations() { + Annotation[] annotations = AnnotationUtil.getDeclaredAnnotations(ClassForTest.class); + Assert.assertArrayEquals(annotations, ClassForTest.class.getDeclaredAnnotations()); + Assert.assertSame(annotations, AnnotationUtil.getDeclaredAnnotations(ClassForTest.class)); + } + @Test public void testToCombination() { final CombinationAnnotationElement element = AnnotationUtil.toCombination(ClassForTest.class); @@ -115,6 +124,21 @@ public class AnnotationUtilTest { Assert.assertEquals(MetaAnnotationForTest.class, annotation.annotationType()); } + @Test + public void testGetAnnotationAttributes() { + Method[] methods = AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class); + Assert.assertSame(methods, AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class)); + Assert.assertEquals(1, methods.length); + Assert.assertArrayEquals(AnnotationForTest.class.getDeclaredMethods(), methods); + } + + @SneakyThrows + @Test + public void testIsAnnotationAttribute() { + Assert.assertFalse(AnnotationUtil.isAnnotationAttribute(AnnotationForTest.class.getMethod("equals", Object.class))); + Assert.assertTrue(AnnotationUtil.isAnnotationAttribute(AnnotationForTest.class.getMethod("value"))); + } + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) private @interface MetaAnnotationForTest{ diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java index fd8a2f3cc..f3d780342 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java @@ -111,6 +111,7 @@ public class MetaAnnotatedElementTest { new Annotation[]{ annotation4 }, element.getAnnotationsByType(Annotation4.class) ); + Assert.assertEquals(0, element.getAnnotationsByType(None.class).length); } @Test @@ -121,6 +122,7 @@ public class MetaAnnotatedElementTest { new Annotation[]{ annotation4 }, element.getDeclaredAnnotationsByType(Annotation4.class) ); + Assert.assertEquals(0, element.getDeclaredAnnotationsByType(None.class).length); } @Test @@ -168,6 +170,11 @@ public class MetaAnnotatedElementTest { Assert.assertSame(source, element.getElement()); } + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + private @interface None { } + + @Annotation4 // 循环引用 @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) private @interface Annotation1 { diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java new file mode 100644 index 000000000..7482d5b55 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java @@ -0,0 +1,220 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.text.CharSequenceUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.annotation.*; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * test for {@link RepeatableAnnotationCollector} + * + * @author huangchengxing + */ +public class RepeatableAnnotationCollectorTest { + + private static final Annotation1 ANNOTATION1 = Foo.class.getAnnotation(Annotation1.class); + private static final List ANNOTATION2S = Arrays.asList(ANNOTATION1.value()); + private static final List ANNOTATION3S = ANNOTATION2S.stream() + .map(Annotation2::value) + .flatMap(Stream::of) + .collect(Collectors.toList()); + private static final List ANNOTATIONS = new ArrayList<>(); + static { + ANNOTATIONS.add(ANNOTATION1); + ANNOTATIONS.addAll(ANNOTATION2S); + ANNOTATIONS.addAll(ANNOTATION3S); + } + + private static final BiPredicate PREDICATE = (annotation, attribute) -> { + // 属性名需为“value” + if (!CharSequenceUtil.equals("value", attribute.getName())) { + return false; + } + final Class attributeType = attribute.getReturnType(); + // 返回值类型需为数组 + return attributeType.isArray() + // 且数组元素需为注解 + && attributeType.getComponentType() + .isAnnotation() + // 该注解类必须被@Repeatable注解,但不要求与当前属性的声明方法一致 + && attributeType.getComponentType() + .isAnnotationPresent(Repeatable.class); + }; + + @Test + public void testNone() { + RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.none(); + Assert.assertSame(collector, RepeatableAnnotationCollector.none()); + + Assert.assertEquals(0, collector.getRepeatableAnnotations(null).size()); + + Annotation1 annotation = Foo.class.getAnnotation(Annotation1.class); + Assert.assertEquals(Collections.singletonList(annotation), collector.getRepeatableAnnotations(annotation)); + + Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3)); + + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, Annotation3.class)); + Assert.assertTrue(collector.getRepeatableAnnotations(annotation3, Annotation1.class).isEmpty()); + Assert.assertTrue(collector.getRepeatableAnnotations(null, Annotation1.class).isEmpty()); + } + + @Test + public void testNoneWhenAccumulate() { + RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.none(); + Assert.assertSame(collector, RepeatableAnnotationCollector.none()); + + Assert.assertEquals(0, collector.getRepeatableAnnotations(null, true).size()); + + Annotation1 annotation = Foo.class.getAnnotation(Annotation1.class); + Assert.assertEquals(Collections.singletonList(annotation), collector.getRepeatableAnnotations(annotation, true)); + + Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, true)); + } + + @Test + public void testGenericCollector() { + RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.standard(); + Assert.assertSame(collector, RepeatableAnnotationCollector.standard()); + + Annotation1 annotation = Foo.class.getAnnotation(Annotation1.class); + List annotations = Stream.of(annotation.value()) + .map(Annotation2::value) + .flatMap(Stream::of) + .collect(Collectors.toList()); + Assert.assertEquals(annotations, collector.getRepeatableAnnotations(annotation)); + Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1)); + + Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3)); + + Assert.assertEquals(Collections.singletonList(ANNOTATION1), collector.getRepeatableAnnotations(ANNOTATION1, Annotation1.class)); + Assert.assertEquals(ANNOTATION2S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation2.class)); + Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation3.class)); + } + + @Test + public void testGenericCollectorWhenAccumulate() { + RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.standard(); + Assert.assertSame(collector, RepeatableAnnotationCollector.standard()); + + List annotations = new ArrayList<>(); + Annotation1 annotation = Foo.class.getAnnotation(Annotation1.class); + annotations.add(annotation); + annotations.addAll(Arrays.asList(annotation.value())); + Stream.of(annotation.value()) + .map(Annotation2::value) + .flatMap(Stream::of) + .forEach(annotations::add); + Assert.assertEquals(annotations, collector.getRepeatableAnnotations(annotation, true)); + + Assert.assertEquals(ANNOTATIONS, collector.getRepeatableAnnotations(ANNOTATION1, true)); + + Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, true)); + } + + @Test + public void testConditionCollector() { + RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.condition(PREDICATE); + Annotation1 annotation = Foo.class.getAnnotation(Annotation1.class); + List annotations = Stream.of(annotation.value()) + .map(Annotation2::value) + .flatMap(Stream::of) + .collect(Collectors.toList()); + Assert.assertEquals(annotations, collector.getRepeatableAnnotations(annotation)); + + Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1)); + + Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3)); + + Assert.assertEquals(Collections.singletonList(ANNOTATION1), collector.getRepeatableAnnotations(ANNOTATION1, Annotation1.class)); + Assert.assertEquals(ANNOTATION2S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation2.class)); + Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation3.class)); + } + + @Test + public void testConditionCollectorWhenAccumulate() { + RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.condition(PREDICATE); + + List annotations = new ArrayList<>(); + Annotation1 annotation = Foo.class.getAnnotation(Annotation1.class); + annotations.add(annotation); + annotations.addAll(Arrays.asList(annotation.value())); + Stream.of(annotation.value()) + .map(Annotation2::value) + .flatMap(Stream::of) + .forEach(annotations::add); + Assert.assertEquals(annotations, collector.getRepeatableAnnotations(annotation, true)); + Assert.assertEquals(ANNOTATIONS, collector.getRepeatableAnnotations(ANNOTATION1, true)); + + Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, true)); + } + + @Test + public void testFullCollector() { + RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.full(); + Assert.assertSame(collector, RepeatableAnnotationCollector.full()); + + Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1)); + + Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3)); + + Assert.assertEquals(Collections.singletonList(ANNOTATION1), collector.getRepeatableAnnotations(ANNOTATION1, Annotation1.class)); + Assert.assertEquals(ANNOTATION2S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation2.class)); + Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation3.class)); + } + + @Test + public void testFullCollectorWhenAccumulate() { + RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.full(); + Assert.assertSame(collector, RepeatableAnnotationCollector.full()); + + Assert.assertEquals(ANNOTATIONS, collector.getRepeatableAnnotations(ANNOTATION1, true)); + + Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, true)); + } + + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + private @interface Annotation1 { + Annotation2[] value() default {}; + } + + @Repeatable(Annotation1.class) + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + private @interface Annotation2 { + Annotation3[] value() default {}; + } + + @Repeatable(Annotation2.class) + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + private @interface Annotation3 { + int value(); + String name() default ""; + } + + @Annotation3(Integer.MIN_VALUE) + @Annotation1({ + @Annotation2({@Annotation3(1), @Annotation3(2)}), + @Annotation2({@Annotation3(3), @Annotation3(4)}) + }) + private static class Foo {} + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java new file mode 100644 index 000000000..7471e9497 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java @@ -0,0 +1,212 @@ +package cn.hutool.core.annotation; + +import cn.hutool.core.collection.iter.IterUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.annotation.*; +import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +/** + * test for {@link RepeatableMetaAnnotatedElement} + * + * @author huangchengxing + */ +public class RepeatableMetaAnnotatedElementTest { + + private static final BiFunction RESOLVED_MAPPING_FACTORY = + (source, annotation) -> new ResolvedAnnotationMapping(source, annotation, true); + + private static final BiFunction MAPPING_FACTORY = + (source, annotation) -> new ResolvedAnnotationMapping(source, annotation, false); + + @Test + public void testEquals() { + AnnotatedElement element = RepeatableMetaAnnotatedElement.create(Foo.class, RESOLVED_MAPPING_FACTORY); + Assert.assertEquals(element, element); + Assert.assertNotEquals(element, null); + Assert.assertEquals(element, RepeatableMetaAnnotatedElement.create(Foo.class, RESOLVED_MAPPING_FACTORY)); + Assert.assertNotEquals(element, RepeatableMetaAnnotatedElement.create(Foo.class, MAPPING_FACTORY)); + Assert.assertNotEquals(element, RepeatableMetaAnnotatedElement.create(Annotation1.class, MAPPING_FACTORY)); + } + + @Test + public void testHashCode() { + int hashCode = RepeatableMetaAnnotatedElement.create(Foo.class, RESOLVED_MAPPING_FACTORY).hashCode(); + Assert.assertEquals(hashCode, RepeatableMetaAnnotatedElement.create(Foo.class, RESOLVED_MAPPING_FACTORY).hashCode()); + Assert.assertNotEquals(hashCode, RepeatableMetaAnnotatedElement.create(Foo.class, MAPPING_FACTORY).hashCode()); + Assert.assertNotEquals(hashCode, RepeatableMetaAnnotatedElement.create(Annotation1.class, MAPPING_FACTORY).hashCode()); + } + + @Test + public void testIsAnnotationPresent() { + AnnotatedElement element = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), Foo.class, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + Assert.assertTrue(element.isAnnotationPresent(Annotation1.class)); + Assert.assertTrue(element.isAnnotationPresent(Annotation2.class)); + Assert.assertTrue(element.isAnnotationPresent(Annotation3.class)); + Assert.assertTrue(element.isAnnotationPresent(Annotation4.class)); + } + + @Test + public void testGetAnnotations() { + AnnotatedElement element = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), Foo.class, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + List> annotationTypes = Arrays.stream(element.getAnnotations()) + .map(Annotation::annotationType) + .collect(Collectors.toList()); + Map, Integer> countMap = IterUtil.countMap(annotationTypes.iterator()); + + Assert.assertEquals((Integer)1, countMap.get(Annotation1.class)); + Assert.assertEquals((Integer)2, countMap.get(Annotation2.class)); + Assert.assertEquals((Integer)4, countMap.get(Annotation3.class)); + Assert.assertEquals((Integer)7, countMap.get(Annotation4.class)); + } + + @Test + public void testGetAnnotation() { + AnnotatedElement element = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), Foo.class, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + + Annotation1 annotation1 = Foo.class.getAnnotation(Annotation1.class); + Assert.assertEquals(annotation1, element.getAnnotation(Annotation1.class)); + + Annotation4 annotation4 = Annotation1.class.getAnnotation(Annotation4.class); + Assert.assertEquals(annotation4, element.getAnnotation(Annotation4.class)); + + Annotation2 annotation2 = annotation1.value()[0]; + Assert.assertEquals(annotation2, element.getAnnotation(Annotation2.class)); + + Annotation3 annotation3 = annotation2.value()[0]; + Assert.assertEquals(annotation3, element.getAnnotation(Annotation3.class)); + } + + @Test + public void testGetAnnotationsByType() { + AnnotatedElement element = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), Foo.class, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + + Annotation[] annotations = element.getAnnotationsByType(Annotation1.class); + Assert.assertEquals(1, annotations.length); + + annotations = element.getAnnotationsByType(Annotation2.class); + Assert.assertEquals(2, annotations.length); + + annotations = element.getAnnotationsByType(Annotation3.class); + Assert.assertEquals(4, annotations.length); + + annotations = element.getAnnotationsByType(Annotation4.class); + Assert.assertEquals(7, annotations.length); + } + + @Test + public void testGetDeclaredAnnotations() { + AnnotatedElement element = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), Foo.class, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + List> annotationTypes = Arrays.stream(element.getDeclaredAnnotations()) + .map(Annotation::annotationType) + .collect(Collectors.toList()); + Map, Integer> countMap = IterUtil.countMap(annotationTypes.iterator()); + + Assert.assertEquals((Integer)1, countMap.get(Annotation1.class)); + Assert.assertFalse(countMap.containsKey(Annotation2.class)); + Assert.assertFalse(countMap.containsKey(Annotation3.class)); + Assert.assertFalse(countMap.containsKey(Annotation4.class)); + } + + @Test + public void testGetDeclaredAnnotation() { + AnnotatedElement element = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), Foo.class, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + + Annotation1 annotation1 = Foo.class.getDeclaredAnnotation(Annotation1.class); + Assert.assertEquals(annotation1, element.getDeclaredAnnotation(Annotation1.class)); + Assert.assertNull(element.getDeclaredAnnotation(Annotation3.class)); + Assert.assertNull(element.getDeclaredAnnotation(Annotation4.class)); + Assert.assertNull(element.getDeclaredAnnotation(Annotation2.class)); + } + + @Test + public void testGetDeclaredAnnotationsByType() { + AnnotatedElement element = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), Foo.class, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + + Annotation[] annotations = element.getDeclaredAnnotationsByType(Annotation1.class); + Assert.assertEquals(1, annotations.length); + + annotations = element.getDeclaredAnnotationsByType(Annotation2.class); + Assert.assertEquals(0, annotations.length); + + annotations = element.getDeclaredAnnotationsByType(Annotation3.class); + Assert.assertEquals(0, annotations.length); + + annotations = element.getDeclaredAnnotationsByType(Annotation4.class); + Assert.assertEquals(0, annotations.length); + } + + @Test + public void testGetElement() { + AnnotatedElement element = Foo.class; + RepeatableMetaAnnotatedElement repeatableMetaAnnotatedElement = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), element, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + Assert.assertSame(element, repeatableMetaAnnotatedElement.getElement()); + } + + @Test + public void testIterator() { + RepeatableMetaAnnotatedElement element = RepeatableMetaAnnotatedElement.create( + RepeatableAnnotationCollector.standard(), Foo.class, (s, a) -> new GenericAnnotationMapping(a, Objects.isNull(s)) + ); + int count = 0; + for (GenericAnnotationMapping mapping : element) { + count++; + } + Assert.assertEquals(14, count); + } + + @Annotation4 + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + private @interface Annotation1 { + Annotation2[] value() default {}; + } + + @Annotation4 + @Repeatable(Annotation1.class) + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + private @interface Annotation2 { + Annotation3[] value() default {}; + } + + @Annotation4 + @Repeatable(Annotation2.class) + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + private @interface Annotation3 { } + + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + private @interface Annotation4 { } + + @Annotation1({ + @Annotation2({@Annotation3, @Annotation3}), + @Annotation2({@Annotation3, @Annotation3}) + }) + private static class Foo {} + +} From de06d8777caead71954766f803654e9735580d32 Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Wed, 21 Sep 2022 18:18:55 +0800 Subject: [PATCH 31/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BD=93=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=E5=AD=98=E5=9C=A8=E5=BE=AA=E7=8E=AF=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E6=97=B6=E6=8A=A5=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotation/MetaAnnotatedElement.java | 15 +++++++++------ .../RepeatableMetaAnnotatedElement.java | 15 +++++++++------ .../core/annotation/AnnotatedElementUtilTest.java | 1 + .../core/annotation/MetaAnnotatedElementTest.java | 1 + .../RepeatableMetaAnnotatedElementTest.java | 1 + 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/MetaAnnotatedElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/MetaAnnotatedElement.java index 313642514..a10ac07d9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/MetaAnnotatedElement.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/MetaAnnotatedElement.java @@ -10,7 +10,6 @@ import java.lang.annotation.Inherited; import java.lang.reflect.AnnotatedElement; import java.util.*; import java.util.function.BiFunction; -import java.util.stream.Stream; /** *

    注解元素映射,用于包装一个{@link AnnotatedElement},然后将被包装的元素上, @@ -314,11 +313,15 @@ public class MetaAnnotatedElement> imple } // 保存该注解,并将其需要处理的元注解也加入队列 mappings.put(mapping.annotationType(), mapping); - Stream.of(AnnotationUtil.getDeclaredAnnotations(mapping.annotationType())) - .map(annotation -> createMapping(mapping, annotation)) - .filter(Objects::nonNull) - .filter(m -> isNeedMapping(mappings, m)) - .forEach(deque::addLast); + for (final Annotation annotation : AnnotationUtil.getDeclaredAnnotations(mapping.annotationType())) { + if (mappings.containsKey(annotation.annotationType())) { + continue; + } + final T m = createMapping(mapping, annotation); + if (Objects.nonNull(m) && isNeedMapping(mappings, m)) { + deque.addLast(m); + } + } } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java index bca63a030..bc10645c7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java @@ -10,7 +10,6 @@ import java.lang.reflect.AnnotatedElement; import java.util.*; import java.util.function.BiFunction; import java.util.stream.Collectors; -import java.util.stream.Stream; /** *

    支持可重复注解的增强{@link AnnotatedElement}, @@ -347,11 +346,15 @@ public class RepeatableMetaAnnotatedElement mappingFactory.apply(source, annotation)) - .filter(Objects::nonNull) - .filter(m -> isNeedMapping(collectedMappings, m)) - .forEach(deque::addLast); + for (final Annotation annotation : AnnotationUtil.getDeclaredAnnotations(source.annotationType())) { + if (collectedMappings.containsKey(annotation.annotationType())) { + continue; + } + final T mapping = mappingFactory.apply(source, annotation); + if (Objects.nonNull(mapping) && isNeedMapping(collectedMappings, mapping)) { + deque.addLast(mapping); + } + } } return collectedMappings; } diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java index 9b2fe5b85..5585b657e 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java @@ -572,6 +572,7 @@ public class AnnotatedElementUtilTest { // ================= interface ================= + @Annotation6 @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) private @interface Annotation5 {} diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java index f3d780342..f4cdfdc1d 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/MetaAnnotatedElementTest.java @@ -170,6 +170,7 @@ public class MetaAnnotatedElementTest { Assert.assertSame(source, element.getElement()); } + @Annotation4 // 循环引用 @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) private @interface None { } diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java index 7471e9497..2fc38fe03 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElementTest.java @@ -199,6 +199,7 @@ public class RepeatableMetaAnnotatedElementTest { @Retention(RetentionPolicy.RUNTIME) private @interface Annotation3 { } + @Annotation4 // 循环引用 @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) private @interface Annotation4 { } From 84db7222f0c0267ad19a061b8f992f3eb9bff8a5 Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Wed, 21 Sep 2022 19:06:24 +0800 Subject: [PATCH 32/73] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RepeatableAnnotationCollector.java | 71 ++++++++++++++----- .../RepeatableMetaAnnotatedElement.java | 2 +- .../RepeatableAnnotationCollectorTest.java | 44 ++++++------ 3 files changed, 77 insertions(+), 40 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java index 38579178d..1daae6cdb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java @@ -32,9 +32,20 @@ public interface RepeatableAnnotationCollector { } /** - * 当注解中有且仅有一个名为{@code value}的属性时, + *

    当注解中有且仅有一个名为{@code value}的属性时, * 若该属性类型为注解数组,且该数组对应的注解类型被{@link Repeatable}注解, - * 则收集器将返回该属性中包括的可重复注解。 + * 则收集器将返回该属性中包括的可重复注解。
    + * eg: + *

    
    +	 * // 容器注解
    +	 * {@literal @}interface Annotation {
    +	 * 	Item[] value() default {};
    +	 * }
    +	 * // 可重复注解
    +	 * {@literal @}Repeatable(Annotation.class)
    +	 * {@literal @}interface Item {}
    +	 * 
    + * 解析任意{@code Annotation}注解对象,则可以获得{@code value}属性中的{@code Item}注解对象 * * @return {@link RepeatableAnnotationCollector}实例 * @see Standard @@ -55,9 +66,19 @@ public interface RepeatableAnnotationCollector { } /** - * 当注解中存在有属性为注解数组,且该数组对应的注解类型被{@link Repeatable}注解时, + *

    当注解中存在有属性为注解数组,且该数组对应的注解类型被{@link Repeatable}注解时, * 认为该属性包含可重复注解。
    - * 收集器将返回所有符合上述条件的属性中的可重复注解。 + * 收集器将返回所有符合上述条件的属性中的可重复注解。
    + * eg: + *

    
    +	 * {@literal @}interface Annotation {
    +	 * 	Item1[] items1() default {};
    +	 * 	Item2[] items2() default {};
    +	 * }
    +	 * 
    + * 解析任意{@code Annotation}注解对象, + * 则可以获得{@code items1}属性中的{@code Item1}注解对象, + * 以及{@code items2}属性中的{@code Item2}注解对象, * * @return {@link RepeatableAnnotationCollector}实例 */ @@ -67,26 +88,39 @@ public interface RepeatableAnnotationCollector { /** *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 - * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。 + * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
    + * eg: + * 若存在嵌套关系{@code a -> b -> c}, + * 则解析注解a,则将得到全部c注解。
    + * 如果注解不包含可重复注解,则返回a本身。 * * @param annotation 容器注解 * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象 */ - List getRepeatableAnnotations(final Annotation annotation); + List getFinalRepeatableAnnotations(final Annotation annotation); /** *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
    - * 当{@code accumulate}为{@code true}时,返回结果为全量的注解。 + * eg: + * 若存在嵌套关系{@code a -> b -> c},则解析注解a, + * 将获得全部abc注解。
    + * 如果注解不包含可重复注解,则返回a本身。 * * @param annotation 容器注解 - * @param accumulate 是否累加 * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象 */ - List getRepeatableAnnotations(final Annotation annotation, final boolean accumulate); + List getAllRepeatableAnnotations(final Annotation annotation); /** - * 若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的指定类型注解对象 + *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的指定类型注解对象。
    + * eg: + * 若存在嵌套关系{@code a -> b -> c},则: + *

      + *
    • 解析注解a:可获得abc
    • + *
    • 解析注解b:可获得bc
    • + *
    • 解析注解c:只可获得c
    • + *
    * * @param annotation 容器注解 * @param annotationType 注解类型 @@ -112,7 +146,7 @@ public interface RepeatableAnnotationCollector { * @return 空集合 */ @Override - public List getRepeatableAnnotations(final Annotation annotation) { + public List getFinalRepeatableAnnotations(final Annotation annotation) { return Objects.isNull(annotation) ? Collections.emptyList() : Collections.singletonList(annotation); } @@ -124,7 +158,7 @@ public interface RepeatableAnnotationCollector { * @return 空集合 */ @Override - public List getRepeatableAnnotations(final Annotation annotation, final boolean accumulate) { + public List getAllRepeatableAnnotations(final Annotation annotation) { return Objects.isNull(annotation) ? Collections.emptyList() : Collections.singletonList(annotation); } @@ -159,22 +193,25 @@ public interface RepeatableAnnotationCollector { * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象 */ @Override - public final List getRepeatableAnnotations(final Annotation annotation) { - return getRepeatableAnnotations(annotation, false); + public final List getFinalRepeatableAnnotations(final Annotation annotation) { + return find(annotation, null, false); } /** *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
    * 当{@code accumulate}为{@code true}时,返回结果为全量的注解。 + * eg: + * 若存在嵌套关系{@code a -> b -> c},则解析注解a, + * 将获得全部abc注解。 + * 如果注解不包含可重复注解,则返回其本身。 * * @param annotation 容器注解 - * @param accumulate 是否累加 * @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象 */ @Override - public final List getRepeatableAnnotations(final Annotation annotation, final boolean accumulate) { - return find(annotation, null, accumulate); + public List getAllRepeatableAnnotations(Annotation annotation) { + return find(annotation, null, true); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java index bc10645c7..1c2894a5d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java @@ -285,7 +285,7 @@ public class RepeatableMetaAnnotatedElement collectRepeatable(final Annotation annotation) { - return repeatableCollector.getRepeatableAnnotations(annotation, true) + return repeatableCollector.getAllRepeatableAnnotations(annotation) .stream() .map(a -> new Aggregation(a, Objects.equals(a, annotation))) .collect(Collectors.toList()); diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java index 7482d5b55..ac9386a57 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/RepeatableAnnotationCollectorTest.java @@ -55,13 +55,13 @@ public class RepeatableAnnotationCollectorTest { RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.none(); Assert.assertSame(collector, RepeatableAnnotationCollector.none()); - Assert.assertEquals(0, collector.getRepeatableAnnotations(null).size()); + Assert.assertEquals(0, collector.getFinalRepeatableAnnotations(null).size()); Annotation1 annotation = Foo.class.getAnnotation(Annotation1.class); - Assert.assertEquals(Collections.singletonList(annotation), collector.getRepeatableAnnotations(annotation)); + Assert.assertEquals(Collections.singletonList(annotation), collector.getFinalRepeatableAnnotations(annotation)); Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); - Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3)); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getFinalRepeatableAnnotations(annotation3)); Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, Annotation3.class)); Assert.assertTrue(collector.getRepeatableAnnotations(annotation3, Annotation1.class).isEmpty()); @@ -73,13 +73,13 @@ public class RepeatableAnnotationCollectorTest { RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.none(); Assert.assertSame(collector, RepeatableAnnotationCollector.none()); - Assert.assertEquals(0, collector.getRepeatableAnnotations(null, true).size()); + Assert.assertEquals(0, collector.getAllRepeatableAnnotations(null).size()); Annotation1 annotation = Foo.class.getAnnotation(Annotation1.class); - Assert.assertEquals(Collections.singletonList(annotation), collector.getRepeatableAnnotations(annotation, true)); + Assert.assertEquals(Collections.singletonList(annotation), collector.getAllRepeatableAnnotations(annotation)); Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); - Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, true)); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getAllRepeatableAnnotations(annotation3)); } @Test @@ -92,11 +92,11 @@ public class RepeatableAnnotationCollectorTest { .map(Annotation2::value) .flatMap(Stream::of) .collect(Collectors.toList()); - Assert.assertEquals(annotations, collector.getRepeatableAnnotations(annotation)); - Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1)); + Assert.assertEquals(annotations, collector.getFinalRepeatableAnnotations(annotation)); + Assert.assertEquals(ANNOTATION3S, collector.getFinalRepeatableAnnotations(ANNOTATION1)); Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); - Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3)); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getFinalRepeatableAnnotations(annotation3)); Assert.assertEquals(Collections.singletonList(ANNOTATION1), collector.getRepeatableAnnotations(ANNOTATION1, Annotation1.class)); Assert.assertEquals(ANNOTATION2S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation2.class)); @@ -116,12 +116,12 @@ public class RepeatableAnnotationCollectorTest { .map(Annotation2::value) .flatMap(Stream::of) .forEach(annotations::add); - Assert.assertEquals(annotations, collector.getRepeatableAnnotations(annotation, true)); + Assert.assertEquals(annotations, collector.getAllRepeatableAnnotations(annotation)); - Assert.assertEquals(ANNOTATIONS, collector.getRepeatableAnnotations(ANNOTATION1, true)); + Assert.assertEquals(ANNOTATIONS, collector.getAllRepeatableAnnotations(ANNOTATION1)); Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); - Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, true)); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getAllRepeatableAnnotations(annotation3)); } @Test @@ -132,12 +132,12 @@ public class RepeatableAnnotationCollectorTest { .map(Annotation2::value) .flatMap(Stream::of) .collect(Collectors.toList()); - Assert.assertEquals(annotations, collector.getRepeatableAnnotations(annotation)); + Assert.assertEquals(annotations, collector.getFinalRepeatableAnnotations(annotation)); - Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1)); + Assert.assertEquals(ANNOTATION3S, collector.getFinalRepeatableAnnotations(ANNOTATION1)); Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); - Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3)); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getFinalRepeatableAnnotations(annotation3)); Assert.assertEquals(Collections.singletonList(ANNOTATION1), collector.getRepeatableAnnotations(ANNOTATION1, Annotation1.class)); Assert.assertEquals(ANNOTATION2S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation2.class)); @@ -156,11 +156,11 @@ public class RepeatableAnnotationCollectorTest { .map(Annotation2::value) .flatMap(Stream::of) .forEach(annotations::add); - Assert.assertEquals(annotations, collector.getRepeatableAnnotations(annotation, true)); - Assert.assertEquals(ANNOTATIONS, collector.getRepeatableAnnotations(ANNOTATION1, true)); + Assert.assertEquals(annotations, collector.getAllRepeatableAnnotations(annotation)); + Assert.assertEquals(ANNOTATIONS, collector.getAllRepeatableAnnotations(ANNOTATION1)); Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); - Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, true)); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getAllRepeatableAnnotations((annotation3))); } @Test @@ -168,10 +168,10 @@ public class RepeatableAnnotationCollectorTest { RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.full(); Assert.assertSame(collector, RepeatableAnnotationCollector.full()); - Assert.assertEquals(ANNOTATION3S, collector.getRepeatableAnnotations(ANNOTATION1)); + Assert.assertEquals(ANNOTATION3S, collector.getFinalRepeatableAnnotations(ANNOTATION1)); Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); - Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3)); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getFinalRepeatableAnnotations(annotation3)); Assert.assertEquals(Collections.singletonList(ANNOTATION1), collector.getRepeatableAnnotations(ANNOTATION1, Annotation1.class)); Assert.assertEquals(ANNOTATION2S, collector.getRepeatableAnnotations(ANNOTATION1, Annotation2.class)); @@ -183,10 +183,10 @@ public class RepeatableAnnotationCollectorTest { RepeatableAnnotationCollector collector = RepeatableAnnotationCollector.full(); Assert.assertSame(collector, RepeatableAnnotationCollector.full()); - Assert.assertEquals(ANNOTATIONS, collector.getRepeatableAnnotations(ANNOTATION1, true)); + Assert.assertEquals(ANNOTATIONS, collector.getAllRepeatableAnnotations(ANNOTATION1)); Annotation3 annotation3 = Foo.class.getAnnotation(Annotation3.class); - Assert.assertEquals(Collections.singletonList(annotation3), collector.getRepeatableAnnotations(annotation3, true)); + Assert.assertEquals(Collections.singletonList(annotation3), collector.getAllRepeatableAnnotations(annotation3)); } @Target(ElementType.TYPE_USE) From 7932e73395032bc3d76f1ade3809383531d858e2 Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Wed, 21 Sep 2022 19:33:12 +0800 Subject: [PATCH 33/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=8E=B7=E5=BE=97?= =?UTF-8?q?=E7=B1=BB=E7=9B=B4=E6=8E=A5=E5=A3=B0=E6=98=8E=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E7=9A=84=E9=9D=99=E6=80=81=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotation/AnnotationUtil.java | 11 ++------- .../HierarchicalAnnotatedElements.java | 4 ++-- .../cn/hutool/core/reflect/MethodUtil.java | 23 +++++++++++++++---- .../core/annotation/AnnotationUtilTest.java | 2 +- .../hutool/core/reflect/MethodUtilTest.java | 12 ++++++++++ 5 files changed, 35 insertions(+), 17 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index eca5f86b5..b5dd123c5 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -27,11 +27,6 @@ import java.util.stream.Stream; */ public class AnnotationUtil { - /** - * 注解属性缓存 - */ - private static final Map, Method[]> ANNOTATION_ATTRIBUTES_CACHE = new WeakConcurrentMap<>(); - /** * 直接声明的注解缓存 */ @@ -324,11 +319,9 @@ public class AnnotationUtil { * @since 6.0.0 */ public static Method[] getAnnotationAttributes(final Class annotationType) { - return MapUtil.computeIfAbsent( - ANNOTATION_ATTRIBUTES_CACHE, annotationType, type -> Stream.of(annotationType.getDeclaredMethods()) + return Stream.of(MethodUtil.getDeclaredMethods(annotationType)) .filter(AnnotationUtil::isAnnotationAttribute) - .toArray(Method[]::new) - ); + .toArray(Method[]::new); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java b/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java index 152154b56..c159961b1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/HierarchicalAnnotatedElements.java @@ -2,6 +2,7 @@ package cn.hutool.core.annotation; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.reflect.ClassUtil; +import cn.hutool.core.reflect.MethodUtil; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ArrayUtil; @@ -357,8 +358,7 @@ public class HierarchicalAnnotatedElements implements AnnotatedElement, Iterable if (!isMethod) { collectElement(mappings, type); } else { - // TODO 改为通过带缓存的反射工具类完成 - Stream.of(type.getDeclaredMethods()) + Stream.of(MethodUtil.getDeclaredMethods(type)) .filter(method -> isMatchMethod(methodSource, method)) .forEach(method -> collectElement(mappings, method)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java index 6b212c9d2..f7368527f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java @@ -15,11 +15,7 @@ import cn.hutool.core.util.ArrayUtil; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.function.Predicate; /** @@ -33,6 +29,10 @@ public class MethodUtil { * 方法缓存 */ private static final WeakConcurrentMap, Method[]> METHODS_CACHE = new WeakConcurrentMap<>(); + /** + * 直接声明的方法缓存 + */ + private static final WeakConcurrentMap, Method[]> DECLARED_METHODS_CACHE = new WeakConcurrentMap<>(); // --------------------------------------------------------------------------------------------------------- method @@ -323,6 +323,19 @@ public class MethodUtil { (key) -> getMethodsDirectly(beanClass, true, true)); } + /** + * 获得类中所有直接声明方法,不包括其父类中的方法 + * + * @param beanClass 类,非{@code null} + * @return 方法列表 + * @throws SecurityException 安全检查异常 + */ + public static Method[] getDeclaredMethods(final Class beanClass) throws SecurityException { + Assert.notNull(beanClass); + return DECLARED_METHODS_CACHE.computeIfAbsent(beanClass, + key -> getMethodsDirectly(beanClass, false, Objects.equals(Object.class, beanClass))); + } + /** * 获得一个类中所有方法列表,直接反射获取,无缓存
    * 接口获取方法和默认方法,获取的方法包括: diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java index ebd3cdb44..a1f1eb380 100755 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java @@ -127,7 +127,7 @@ public class AnnotationUtilTest { @Test public void testGetAnnotationAttributes() { Method[] methods = AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class); - Assert.assertSame(methods, AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class)); + Assert.assertArrayEquals(methods, AnnotationUtil.getAnnotationAttributes(AnnotationForTest.class)); Assert.assertEquals(1, methods.length); Assert.assertArrayEquals(AnnotationForTest.class.getDeclaredMethods(), methods); } diff --git a/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java index 7322a9a70..5919e66c3 100644 --- a/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java @@ -81,6 +81,18 @@ public class MethodUtilTest { Assert.assertEquals(10, testClass.getA()); } + @Test + public void getDeclaredMethodsTest() { + Class type = ReflectUtilTest.TestBenchClass.class; + Method[] methods = type.getDeclaredMethods(); + Assert.assertArrayEquals(methods, MethodUtil.getDeclaredMethods(type)); + Assert.assertSame(MethodUtil.getDeclaredMethods(type), MethodUtil.getDeclaredMethods(type)); + + type = Object.class; + methods = type.getDeclaredMethods(); + Assert.assertArrayEquals(methods, MethodUtil.getDeclaredMethods(type)); + } + @Test @Ignore public void getMethodBenchTest() { From bf76657b1232161e89cb77f27cfcc4e76f450e09 Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 22 Sep 2022 09:45:58 +0800 Subject: [PATCH 34/73] fix doc --- .../core/annotation/RepeatableMetaAnnotatedElement.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java index 1c2894a5d..811307439 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableMetaAnnotatedElement.java @@ -5,7 +5,6 @@ import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ArrayUtil; import java.lang.annotation.Annotation; -import java.lang.annotation.Repeatable; import java.lang.reflect.AnnotatedElement; import java.util.*; import java.util.function.BiFunction; @@ -20,9 +19,9 @@ import java.util.stream.Collectors; * 即当{@link AnnotatedElement}存在多个根注解有相同的元注解时,这些元注解会都会被扫描到; * *

  • - * 支持扫描{@link AnnotatedElement}可重复注解,即当{@link AnnotatedElement}上直接声明的注解 - * 有且仅有一个类型为注解数组的{@code value}属性,且数组中注解类上存在{@link Repeatable}, - * 则认为该注解为容器注解,将会自动将其展开直到不为容器注解为止。
    + * 支持扫描{@link AnnotatedElement}可重复注解,即当当前实例指定的{@link RepeatableAnnotationCollector} + * 支持从{@link AnnotatedElement}上直接声明的注解中获得可重复注解时, + * 则将会自动将其展开直到不为容器注解为止。
    * eg:
    * A上存在注解X,该注解是一个容器注解,内部可重复注解Y, * 包含解析后,得到注解X与可重复注解Y,
    From dbbccf3fc8ac172510fc970cb90ed62c8cec366e Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 22 Sep 2022 14:09:19 +0800 Subject: [PATCH 35/73] =?UTF-8?q?=E6=B3=A8=E8=A7=A3=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E6=94=AF=E6=8C=81=E4=B8=BB=E5=8A=A8=E6=B8=85=E7=A9=BA?= =?UTF-8?q?=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotation/AnnotatedElementUtil.java | 38 ++++++++++++++++--- .../core/annotation/AnnotationUtil.java | 7 ++++ .../RepeatableAnnotationCollector.java | 8 ++++ .../annotation/AnnotatedElementUtilTest.java | 25 ++++++++++++ .../core/annotation/AnnotationUtilTest.java | 3 ++ 5 files changed, 75 insertions(+), 6 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java index 62c81f338..34ee2974b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java @@ -103,8 +103,8 @@ import java.util.stream.Stream; * 该属性类型为注解数组,且数组中注解被{@link java.lang.annotation.Repeatable}注解, * 则认为被包括的注解为可重复注解;
    * eg:
    - * A上存在注解X,该注解是一个容器注解,内部可重复注解Y, - * 包含解析后,得到注解X与它包含的可重复注解Y; + * A上存在注解X,该注解是一个容器注解,内部包含可重复注解Y, + * 解析X后,得到注解X与它包含的可重复注解Y; *
  • *
  • * 若{@link AnnotatedElement}存在直接声明的注解,该注解与其他根注解皆有相同的元注解, @@ -115,6 +115,12 @@ import java.util.stream.Stream; *
  • * * + *

    缓存 + *

    为了避免注解以及{@link AnnotatedElement}层级结构解析过程中的大量反射调用, + * 工具类为{@link AnnotatedElement}及其元注解信息进行了缓存。
    + * 缓存功能默认基于{@link WeakConcurrentMap}实现,会在gc时自动回收部分缓存数据。 + * 但是若有必要,也可以调用{@link #clearCaches()}方法主动清空缓存。 + * * @author huangchengxing * @see ResolvedAnnotationMapping * @see GenericAnnotationMapping @@ -650,7 +656,7 @@ public class AnnotatedElementUtil { * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 */ - private static MetaAnnotatedElement getResolvedMetaElementCache(final AnnotatedElement element) { + static MetaAnnotatedElement getResolvedMetaElementCache(final AnnotatedElement element) { return RESOLVED_ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create( element, (source, annotation) -> ResolvedAnnotationMapping.create(source, annotation, true) )); @@ -662,7 +668,7 @@ public class AnnotatedElementUtil { * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 */ - private static MetaAnnotatedElement getMetaElementCache(final AnnotatedElement element) { + static MetaAnnotatedElement getMetaElementCache(final AnnotatedElement element) { return ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create( element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source)) )); @@ -674,7 +680,7 @@ public class AnnotatedElementUtil { * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 */ - private static RepeatableMetaAnnotatedElement getResolvedRepeatableMetaElementCache(final AnnotatedElement element) { + static RepeatableMetaAnnotatedElement getResolvedRepeatableMetaElementCache(final AnnotatedElement element) { return RESOLVED_REPEATABLE_ELEMENT_CACHE.computeIfAbsent(element, ele -> RepeatableMetaAnnotatedElement.create( element, (source, annotation) -> ResolvedAnnotationMapping.create(source, annotation, true) )); @@ -686,7 +692,7 @@ public class AnnotatedElementUtil { * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 */ - private static RepeatableMetaAnnotatedElement getRepeatableMetaElementCache(final AnnotatedElement element) { + static RepeatableMetaAnnotatedElement getRepeatableMetaElementCache(final AnnotatedElement element) { return REPEATABLE_ELEMENT_CACHE.computeIfAbsent(element, ele -> RepeatableMetaAnnotatedElement.create( element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source)) )); @@ -694,6 +700,26 @@ public class AnnotatedElementUtil { // endregion + /** + * 清空相关缓存,包括: + *

      + *
    • {@link AnnotatedElementUtil}中的{@link AnnotatedElement}及{@link AnnotationMapping}缓存;
    • + *
    • {@link AnnotationUtil}中的{@link AnnotatedElement}上直接声明的注解缓存;
    • + *
    • {@link RepeatableAnnotationCollector}中单例的注解属性缓存;
    • + *
    + * + * @see AnnotationUtil#clearCaches() + * @see RepeatableAnnotationCollector#clearSingletonCaches() + */ + public static void clearCaches() { + ELEMENT_CACHE.clear(); + RESOLVED_ELEMENT_CACHE.clear(); + REPEATABLE_ELEMENT_CACHE.clear(); + RESOLVED_REPEATABLE_ELEMENT_CACHE.clear(); + RepeatableAnnotationCollector.clearSingletonCaches(); + AnnotationUtil.clearCaches(); + } + /** * 由一组注解聚合来的{@link AnnotatedElement} */ diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index b5dd123c5..6691928d6 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -354,4 +354,11 @@ public class AnnotationUtil { && !attribute.isSynthetic(); } + /** + * 清空相关缓存 + */ + public static void clearCaches() { + DECLARED_ANNOTATIONS_CACHE.clear(); + } + } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java index 1daae6cdb..cf6fe2bed 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java @@ -86,6 +86,14 @@ public interface RepeatableAnnotationCollector { return Full.INSTANCE; } + /** + * 清空单例缓存 + */ + static void clearSingletonCaches() { + Standard.INSTANCE.repeatableMethodCache.clear(); + Full.INSTANCE.repeatableMethodCache.clear(); + } + /** *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
    diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java index 5585b657e..7445efde8 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java @@ -37,6 +37,31 @@ public class AnnotatedElementUtilTest { ANNOTATION6, ANNOTATION5 // Interface.class's annotations }; + @Test + public void testClearCaches() { + AnnotatedElement type = Foo.class; + + AnnotatedElement element = AnnotatedElementUtil.getResolvedMetaElementCache(type); + Assert.assertSame(element, AnnotatedElementUtil.getResolvedMetaElementCache(type)); + AnnotatedElementUtil.clearCaches(); + Assert.assertNotSame(element, AnnotatedElementUtil.getResolvedMetaElementCache(type)); + + element = AnnotatedElementUtil.getMetaElementCache(type); + Assert.assertSame(element, AnnotatedElementUtil.getMetaElementCache(type)); + AnnotatedElementUtil.clearCaches(); + Assert.assertNotSame(element, AnnotatedElementUtil.getMetaElementCache(type)); + + element = AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type); + Assert.assertSame(element, AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type)); + AnnotatedElementUtil.clearCaches(); + Assert.assertNotSame(element, AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type)); + + element = AnnotatedElementUtil.getRepeatableMetaElementCache(type); + Assert.assertSame(element, AnnotatedElementUtil.getRepeatableMetaElementCache(type)); + AnnotatedElementUtil.clearCaches(); + Assert.assertNotSame(element, AnnotatedElementUtil.getRepeatableMetaElementCache(type)); + } + @Test public void testIsAnnotated() { Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation1.class)); diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java index a1f1eb380..6053d8851 100755 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java @@ -19,6 +19,9 @@ public class AnnotationUtilTest { Annotation[] annotations = AnnotationUtil.getDeclaredAnnotations(ClassForTest.class); Assert.assertArrayEquals(annotations, ClassForTest.class.getDeclaredAnnotations()); Assert.assertSame(annotations, AnnotationUtil.getDeclaredAnnotations(ClassForTest.class)); + + AnnotationUtil.clearCaches(); + Assert.assertNotSame(annotations, AnnotationUtil.getDeclaredAnnotations(ClassForTest.class)); } @Test From cbcac94b81338a0fcc95ddf668e163534766a840 Mon Sep 17 00:00:00 2001 From: duandazhi Date: Fri, 23 Sep 2022 09:23:06 +0800 Subject: [PATCH 36/73] =?UTF-8?q?PULL=5FREQUEST=5FTEMPLATE=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=8F=90=E4=BA=A4=E5=89=8D=E8=87=AA=E6=B5=8B=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitee/PULL_REQUEST_TEMPLATE.zh-CN.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md index 735406ddc..e80f21900 100644 --- a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md +++ b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md @@ -7,4 +7,13 @@ ### 修改描述(包括说明bug修复或者添加新特性) 1. [bug修复] balabala…… -2. [新特性] balabala…… \ No newline at end of file +2. [新特性] balabala…… + +### 提交前自测 +> 请在提交前自测确保代码没有问题,提交新代码应包含:测试用例、通过(mvn javadoc:javadoc)检验详细注释。 + +1. 本地如有多个JDK版本,可以设置临时JDk版本,如:`export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_331.jdk/Contents/Home`,具体替换为本地jdk目录 +2. 确保本地测试使用JDK8最新版本,`echo $JAVA_HOME`、`mvn -v`、`java -version`均正确。 +3. 执行打包生成文档,使用`mvn clean package -Dmaven.test.skip=true -U`,并确认通过,会自动执行打包、生成文档 +4. 如需要单独执行文档生成,执行:`mvn javadoc:javadoc `,并确认通过 +5. 如需要单独执行测试用例,执行:`mvn clean test`,并确认通过 From 8206176db9b4f79e025f4ed499cc8121bde05088 Mon Sep 17 00:00:00 2001 From: Zjp <1215582715@qq.com> Date: Fri, 23 Sep 2022 09:36:44 +0800 Subject: [PATCH 37/73] =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=B0=8F=E4=BF=AE?= =?UTF-8?q?=E8=A1=A5:=201.=E4=BC=98=E5=8C=96LambdaUtil=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E8=AF=AD=E5=8F=A5,=20=E4=BC=98=E5=8C=96=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E7=9A=84key=E5=80=BC;=202.=E4=BF=AE=E6=AD=A3ReflectUtil?= =?UTF-8?q?=E7=9A=84javadoc=E6=96=87=E6=A1=A3=E6=98=BE=E7=A4=BA,=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96StringBuilder=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=95=BF=E5=BA=A6;=203.=E4=BC=98=E5=8C=96CharSequenceUtil?= =?UTF-8?q?=E7=9A=84replace=E6=96=B9=E6=B3=95,=20=E4=BC=98=E5=8C=96StringB?= =?UTF-8?q?uilder=E5=88=9D=E5=A7=8B=E5=8C=96=E9=95=BF=E5=BA=A6,=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=B9codePoint=E7=9A=84=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=A4=84=E7=90=86;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/lang/func/LambdaUtil.java | 15 +++------- .../cn/hutool/core/reflect/ReflectUtil.java | 28 +++++++++---------- .../cn/hutool/core/text/CharSequenceUtil.java | 11 ++++---- .../core/text/CharSequenceUtilTest.java | 3 ++ .../java/cn/hutool/core/text/StrUtilTest.java | 6 ++++ 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java index 4bfa0521a..4790332b1 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java @@ -13,7 +13,6 @@ import java.lang.invoke.SerializedLambda; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.Objects; /** * Lambda相关工具类 @@ -23,7 +22,7 @@ import java.util.Objects; */ public class LambdaUtil { - private static final WeakConcurrentMap CACHE = new WeakConcurrentMap<>(); + private static final WeakConcurrentMap CACHE = new WeakConcurrentMap<>(); /** * 通过对象的方法或类的静态方法引用,获取lambda实现类 @@ -73,16 +72,10 @@ public class LambdaUtil { * @return 返回解析后的结果 */ public static LambdaInfo resolve(final T func) { - return CACHE.computeIfAbsent(func.getClass().getName(), (key) -> { + return CACHE.computeIfAbsent(func, (key) -> { final SerializedLambda serializedLambda = _resolve(func); final String methodName = serializedLambda.getImplMethodName(); - final Class implClass; - ClassLoaderUtil.loadClass(serializedLambda.getImplClass().replace("/", "."), true); - try { - implClass = Class.forName(serializedLambda.getImplClass().replace("/", "."), true, Thread.currentThread().getContextClassLoader()); - } catch (final ClassNotFoundException e) { - throw new UtilException(e); - } + final Class implClass = ClassLoaderUtil.loadClass(serializedLambda.getImplClass(), true); if ("".equals(methodName)) { for (final Constructor constructor : implClass.getDeclaredConstructors()) { if (ReflectUtil.getDescriptor(constructor).equals(serializedLambda.getImplMethodSignature())) { @@ -160,7 +153,7 @@ public class LambdaUtil { throw new IllegalArgumentException("Not a lambda expression: " + clazz.getName()); } final Object serLambda = MethodUtil.invoke(func, "writeReplace"); - if (Objects.nonNull(serLambda) && serLambda instanceof SerializedLambda) { + if (serLambda instanceof SerializedLambda) { return (SerializedLambda) serLambda; } throw new UtilException("writeReplace result value is not java.lang.invoke.SerializedLambda"); diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java index 66096417a..727f5a31a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java @@ -30,12 +30,6 @@ public class ReflectUtil { /** * 获取jvm定义的Field Descriptors(字段描述) - * - * @param executable 可执行的反射对象 - * @return 描述符 - * @author VampireAchao - * @see
    jvm定义的Field Descriptors(字段描述) - * @see 关于类型描述符的博客 *

    例:

    *
      *
    • {@code ReflectUtil.getDescriptor(Object.class.getMethod("hashCode")) // "()I"}
    • @@ -44,9 +38,15 @@ public class ReflectUtil { *
    • {@code ReflectUtil.getDescriptor(ReflectUtil.class.getDeclaredMethod("appendDescriptor", Class.clas, StringBuilder.class)) // "(Ljava/lang/Class;Ljava/lang/StringBuilder;)V"}
    • *
    • {@code ReflectUtil.getDescriptor(ArrayUtil.class.getMethod("isEmpty", Object[].class)) // "([Ljava/lang/Object;)Z"}
    • *
    + * + * @param executable 可执行的反射对象 + * @return 描述符 + * @author VampireAchao + * @see jvm定义的Field Descriptors(字段描述) + * @see 关于类型描述符的博客 */ public static String getDescriptor(final Executable executable) { - final StringBuilder stringBuilder = new StringBuilder(); + final StringBuilder stringBuilder = new StringBuilder(32); stringBuilder.append('('); final Class[] parameters = executable.getParameterTypes(); for (final Class parameter : parameters) { @@ -63,12 +63,6 @@ public class ReflectUtil { /** * 获取类型描述符,这是编译成class文件后的二进制名称 - * - * @param clazz 类 - * @return 描述字符串 - * @author VampireAchao - * @see jvm定义的Field Descriptors(字段描述) - * @see 关于类型描述符的博客 *

    例:

    *
      *
    • {@code ReflectUtil.getDescriptor(boolean.class) "Z"}
    • @@ -77,9 +71,15 @@ public class ReflectUtil { *
    • {@code ReflectUtil.getDescriptor(int.class) "I"}
    • *
    • {@code ReflectUtil.getDescriptor(Integer.class) "Ljava/lang/Integer;"}
    • *
    + * + * @param clazz 类 + * @return 描述字符串 + * @author VampireAchao + * @see jvm定义的Field Descriptors(字段描述) + * @see 关于类型描述符的博客 */ public static String getDescriptor(final Class clazz) { - final StringBuilder stringBuilder = new StringBuilder(); + final StringBuilder stringBuilder = new StringBuilder(32); Class currentClass; for (currentClass = clazz; currentClass.isArray(); diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java index 373adc478..da258545e 100755 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java @@ -3366,12 +3366,12 @@ public class CharSequenceUtil extends StrChecker { return originalStr; } - final StringBuilder stringBuilder = new StringBuilder(); + final StringBuilder stringBuilder = new StringBuilder(originalStr.length()); for (int i = 0; i < strLength; i++) { if (i >= startInclude && i < endExclude) { stringBuilder.append(replacedChar); } else { - stringBuilder.append(new String(strCodePoints, i, 1)); + stringBuilder.appendCodePoint(strCodePoints[i]); } } return stringBuilder.toString(); @@ -3406,13 +3406,14 @@ public class CharSequenceUtil extends StrChecker { return originalStr; } - final StringBuilder stringBuilder = new StringBuilder(); + // 新字符串长度 <= 旧长度 - (被替换区间codePoints数量) + 替换字符串长度 + final StringBuilder stringBuilder = new StringBuilder(originalStr.length() - (endExclude - startInclude) + replacedStr.length()); for (int i = 0; i < startInclude; i++) { - stringBuilder.append(new String(strCodePoints, i, 1)); + stringBuilder.appendCodePoint(strCodePoints[i]); } stringBuilder.append(replacedStr); for (int i = endExclude; i < strLength; i++) { - stringBuilder.append(new String(strCodePoints, i, 1)); + stringBuilder.appendCodePoint(strCodePoints[i]); } return stringBuilder.toString(); } diff --git a/hutool-core/src/test/java/cn/hutool/core/text/CharSequenceUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/text/CharSequenceUtilTest.java index 3ae6f70a1..969c4ec30 100755 --- a/hutool-core/src/test/java/cn/hutool/core/text/CharSequenceUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/CharSequenceUtilTest.java @@ -30,6 +30,9 @@ public class CharSequenceUtilTest { final String replace = "SSM15930297701BeryAllen"; final String result = CharSequenceUtil.replace(replace, 5, 12, "***"); Assert.assertEquals("SSM15***01BeryAllen", result); + + String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***"); + Assert.assertEquals("\uD83D\uDE00a***ccdd", emoji); } @Test diff --git a/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java index 95cfe2ebc..3576efbd0 100644 --- a/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java @@ -220,6 +220,9 @@ public class StrUtilTest { Assert.assertEquals("aa****dd", string); string = StrUtil.replace("aabbccdd", 2, 12, '*'); Assert.assertEquals("aa******", string); + + String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, '*'); + Assert.assertEquals("\uD83D\uDE00a****ccdd", emoji); } @Test @@ -627,6 +630,9 @@ public class StrUtilTest { final String replace = "SSM15930297701BeryAllen"; final String result = StrUtil.replace(replace, 5, 12, "***"); Assert.assertEquals("SSM15***01BeryAllen", result); + + String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***"); + Assert.assertEquals("\uD83D\uDE00a***ccdd", emoji); } @Test From 50cb9c61681a9ac94225805871d2eea1f7720ad3 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 23 Sep 2022 12:12:06 +0800 Subject: [PATCH 38/73] fix code --- .../cn/hutool/core/reflect/MethodUtil.java | 17 ++++++++------- .../hutool/core/reflect/MethodUtilTest.java | 21 +++++++++++++++++++ .../java/cn/hutool/core/text/StrUtilTest.java | 6 ++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java index f7368527f..14c960ecd 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/MethodUtil.java @@ -198,18 +198,20 @@ public class MethodUtil { return null; } + Method res = null; final Method[] methods = getMethods(clazz); if (ArrayUtil.isNotEmpty(methods)) { for (final Method method : methods) { if (StrUtil.equals(methodName, method.getName(), ignoreCase) && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes) //排除桥接方法,pr#1965@Github - && false == method.isBridge()) { - return method; + //排除协变桥接方法,pr#1965@Github + && (res == null || res.getReturnType().isAssignableFrom(method.getReturnType()))) { + res = method; } } } - return null; + return res; } /** @@ -265,17 +267,18 @@ public class MethodUtil { return null; } + Method res = null; final Method[] methods = getMethods(clazz); if (ArrayUtil.isNotEmpty(methods)) { for (final Method method : methods) { if (StrUtil.equals(methodName, method.getName(), ignoreCase) - // 排除桥接方法 - && false == method.isBridge()) { - return method; + //排除协变桥接方法,pr#1965@Github + && (res == null || res.getReturnType().isAssignableFrom(method.getReturnType()))) { + res = method; } } } - return null; + return res; } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java index 5919e66c3..1198aa049 100644 --- a/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/reflect/MethodUtilTest.java @@ -115,6 +115,7 @@ public class MethodUtilTest { Console.log(timer.getLastTaskTimeMillis()); } + @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; @@ -193,6 +194,26 @@ public class MethodUtilTest { Assert.assertNotNull(publicSubMethod); final Method privateSubMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "privateSubMethod"); Assert.assertNotNull(privateSubMethod); + } + @Test + public void issue2625Test(){ + // 内部类继承的情况下父类方法会被定义为桥接方法,因此按照pr#1965@Github判断返回值的继承关系来代替判断桥接。 + final Method getThis = MethodUtil.getMethod(A.C.class, "getThis"); + Assert.assertTrue(getThis.isBridge()); + } + + @SuppressWarnings("InnerClassMayBeStatic") + public class A{ + + public class C extends B{ + + } + + protected class B{ + public B getThis(){ + return this; + } + } } } diff --git a/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java index 95cfe2ebc..d95d773e6 100644 --- a/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java @@ -695,4 +695,10 @@ public class StrUtilTest { Assert.assertTrue(CharSequenceUtil.isAllBlank("\u2000")); Assert.assertTrue(CharSequenceUtil.isAllBlank("\u2001")); } + + @Test + public void issue2628Test(){ + final String s = StrUtil.indexedFormat("a{0,number,#}", 1234567); + Assert.assertEquals("a1234567", s); + } } From 18f481e76e63671a5b58201765f892a0757e6cf2 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 23 Sep 2022 12:38:40 +0800 Subject: [PATCH 39/73] fix test --- .../src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java index 76a875b1d..f70b4324d 100755 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java @@ -106,7 +106,7 @@ public class ExcelWriteTest { @Ignore public void writeTest2() { final List row = ListUtil.of("姓名", "加班日期", "下班时间", "加班时长", "餐补", "车补次数", "车补", "总计"); - final ExcelWriter overtimeWriter = ExcelUtil.getWriter("e:/excel/single_line.xlsx"); + final ExcelWriter overtimeWriter = ExcelUtil.getWriter("d:/test/excel/single_line.xlsx"); overtimeWriter.writeRow(row); overtimeWriter.close(); } @@ -126,7 +126,7 @@ public class ExcelWriteTest { writer.writeRow(row2); // 生成文件或导出Excel - writer.flush(FileUtil.file("f:/test/writeWithSheetTest.xlsx")); + writer.flush(FileUtil.file("d:/test/writeWithSheetTest.xlsx")); writer.close(); } From 7358366797a6af0b346ca47e636e9c915915f400 Mon Sep 17 00:00:00 2001 From: duandazhi Date: Fri, 23 Sep 2022 22:00:50 +0800 Subject: [PATCH 40/73] =?UTF-8?q?ReflectUtil=206.x=E6=94=B9=E5=8A=A8?= =?UTF-8?q?=E5=B7=A8=E5=A4=A7=EF=BC=8C=20=E8=BF=9B=E8=A1=8C=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E8=AF=B4=E6=98=8E=EF=BC=9B=20=E8=AE=A9=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=8D=87=E7=BA=A7=E4=B8=8D=E8=BF=B7=E8=8C=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/reflect/ReflectUtil.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java index 66096417a..f34d857b1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java @@ -1,13 +1,26 @@ package cn.hutool.core.reflect; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Method; +import java.lang.reflect.*; /** * 反射工具类 * + *

    + * 本工具类,v6.x进行了重构,原来{@link ReflectUtil}中的方法大部分被移动到了 + * {@link FieldUtil}、{@link MethodUtil}、{@link ModifierUtil}、{@link ConstructorUtil}等中, + * 其他相关方法请参考cn.hutool.core.reflect包下的类,相关类 + *

    + *

    常用方法变更

    + *
      + *
    • 反射修改属性
    • + *
    • {@code ReflectUtil#setFieldValue(Object, String, Object)} --p {@link FieldUtil#setFieldValue(Object, String, Object)}
    • + *
    • 修改private修饰可被外部访问
    • + *
    • {@code ReflectUtil.setAccessible(ReflectUtil.getMethodByName(Xxx.class, "xxxMethodName"))} --p {@link ReflectUtil#setAccessible(AccessibleObject)} --p {@link MethodUtil#getMethodByName(Class, String)}
    • + *
    • 移除final属性
    • + *
    • {@code ReflectUtil.removeFinalModify(Field)} --p {@link ModifierUtil#removeFinalModify(Field)}
    • + *
    + * + * * @author Looly * @since 3.0.9 */ From 62c80a21847fffcee30f6871bb66f26f7db48eb4 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 23 Sep 2022 22:06:59 +0800 Subject: [PATCH 41/73] fix doc --- .../src/main/java/cn/hutool/core/text/CharSequenceUtil.java | 4 ++++ .../src/main/java/cn/hutool/core/text/finder/Finder.java | 6 +++++- .../test/java/cn/hutool/core/text/CharSequenceUtilTest.java | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java index 0b1581c73..ffd27977f 100755 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java @@ -37,6 +37,10 @@ import java.util.function.Supplier; */ public class CharSequenceUtil extends StrChecker { + /** + * 未找到的的位置表示,用-1表示 + * @see Finder#INDEX_NOT_FOUND + */ public static final int INDEX_NOT_FOUND = Finder.INDEX_NOT_FOUND; /** diff --git a/hutool-core/src/main/java/cn/hutool/core/text/finder/Finder.java b/hutool-core/src/main/java/cn/hutool/core/text/finder/Finder.java index f6a1aa049..7a4077c3f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/finder/Finder.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/finder/Finder.java @@ -8,6 +8,9 @@ package cn.hutool.core.text.finder; */ public interface Finder { + /** + * 未找到的的位置表示,用-1表示 + */ int INDEX_NOT_FOUND = -1; /** @@ -28,9 +31,10 @@ public interface Finder { /** * 复位查找器,用于重用对象 + * * @return this */ - default Finder reset(){ + default Finder reset() { return this; } } diff --git a/hutool-core/src/test/java/cn/hutool/core/text/CharSequenceUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/text/CharSequenceUtilTest.java index 969c4ec30..48a525bc2 100755 --- a/hutool-core/src/test/java/cn/hutool/core/text/CharSequenceUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/CharSequenceUtilTest.java @@ -31,7 +31,7 @@ public class CharSequenceUtilTest { final String result = CharSequenceUtil.replace(replace, 5, 12, "***"); Assert.assertEquals("SSM15***01BeryAllen", result); - String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***"); + final String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***"); Assert.assertEquals("\uD83D\uDE00a***ccdd", emoji); } From 1f554b775913fe9f36a9d5edda620b69a4ec3dba Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 23 Sep 2022 23:45:59 +0800 Subject: [PATCH 42/73] fix cod --- .../cn/hutool/core/lang/func/LambdaInfo.java | 129 +++++++++++++----- .../cn/hutool/core/lang/func/LambdaUtil.java | 43 +++--- .../hutool/core/lang/func/SerBiConsumer.java | 8 +- .../cn/hutool/core/lang/func/SerFunction.java | 4 +- .../cn/hutool/core/lang/func/SerSupplier.java | 7 +- .../main/java/cn/hutool/core/map/Dict.java | 15 ++ .../java/cn/hutool/core/lang/DictTest.java | 16 ++- .../extra/template/AbstractTemplate.java | 36 ----- .../cn/hutool/extra/template/Template.java | 37 +++-- .../template/engine/beetl/BeetlTemplate.java | 4 +- .../template/engine/enjoy/EnjoyTemplate.java | 6 +- .../engine/freemarker/FreemarkerTemplate.java | 4 +- .../engine/jetbrick/JetbrickTemplate.java | 4 +- .../template/engine/rythm/RythmTemplate.java | 6 +- .../engine/thymeleaf/ThymeleafTemplate.java | 6 +- .../engine/velocity/VelocityTemplate.java | 6 +- .../template/engine/wit/WitTemplate.java | 3 +- .../main/java/cn/hutool/json/JSONObject.java | 33 +++++ .../java/cn/hutool/setting/AbsSetting.java | 16 +++ .../main/java/cn/hutool/setting/Setting.java | 19 +++ .../java/cn/hutool/setting/dialect/Props.java | 36 ++++- .../java/cn/hutool/setting/PropsTest.java | 10 +- 22 files changed, 314 insertions(+), 134 deletions(-) delete mode 100644 hutool-extra/src/main/java/cn/hutool/extra/template/AbstractTemplate.java diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaInfo.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaInfo.java index bd62c2b22..43bb0ed90 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaInfo.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaInfo.java @@ -1,5 +1,6 @@ package cn.hutool.core.lang.func; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.classloader.ClassLoaderUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.text.StrPool; @@ -11,28 +12,42 @@ import java.lang.reflect.Method; import java.lang.reflect.Type; /** - * 存放lambda信息 + * 存放lambda信息
    + * 此类是{@link SerializedLambda}信息的扩充和补充类,包括: + *
      + *
    • 实例化后的对象方法参数类型,一般用于方法引用
    • + *
    * * @author VampireAchao */ public class LambdaInfo { private static final Type[] EMPTY_TYPE = new Type[0]; + // 实例对象的方法参数类型 private final Type[] instantiatedMethodParameterTypes; + // 方法或构造的参数类型 private final Type[] parameterTypes; private final Type returnType; + // 方法名或构造名称 private final String name; private final Executable executable; private final Class clazz; private final SerializedLambda lambda; + /** + * 构造 + * + * @param executable 构造对象{@link Constructor}或方法对象{@link Method} + * @param lambda 实现了序列化接口的lambda表达式 + */ public LambdaInfo(final Executable executable, final SerializedLambda lambda) { + Assert.notNull(executable, "executable must be not null!"); // return type final boolean isMethod = executable instanceof Method; final boolean isConstructor = executable instanceof Constructor; Assert.isTrue(isMethod || isConstructor, "Unsupported executable type: " + executable.getClass()); this.returnType = isMethod ? - ((Method)executable).getGenericReturnType() : ((Constructor)executable).getDeclaringClass(); + ((Method) executable).getGenericReturnType() : ((Constructor) executable).getDeclaringClass(); // lambda info this.parameterTypes = executable.getGenericParameterTypes(); @@ -42,15 +57,89 @@ public class LambdaInfo { this.lambda = lambda; // types - final int index = lambda.getInstantiatedMethodType().indexOf(";)"); - this.instantiatedMethodParameterTypes = (index > -1) ? getInstantiatedMethodParamTypes(lambda, index) : EMPTY_TYPE; + final String instantiatedMethodType = lambda.getInstantiatedMethodType(); + final int index = instantiatedMethodType.indexOf(";)"); + this.instantiatedMethodParameterTypes = (index > -1) ? + getInstantiatedMethodParamTypes(instantiatedMethodType.substring(1, index + 1)) : EMPTY_TYPE; + } + + /** + * 实例方法参数类型 + * + * @return 实例方法参数类型 + */ + public Type[] getInstantiatedMethodParameterTypes() { + return instantiatedMethodParameterTypes; + } + + /** + * 获得构造或方法参数类型列表 + * + * @return 参数类型列表 + */ + public Type[] getParameterTypes() { + return parameterTypes; + } + + /** + * 获取返回值类型(方法引用) + * + * @return 返回值类型 + */ + public Type getReturnType() { + return returnType; + } + + /** + * 方法或构造名称 + * + * @return 方法或构造名称 + */ + public String getName() { + return name; + } + + /** + * 字段名称,主要用于方法名称截取,方法名称必须为getXXX、isXXX、setXXX + * + * @return getter或setter对应的字段名称 + */ + public String getFieldName() { + return BeanUtil.getFieldName(getName()); + } + + /** + * 方法或构造对象 + * + * @return 方法或构造对象 + */ + public Executable getExecutable() { + return executable; + } + + /** + * 方法或构造所在类 + * + * @return 方法或构造所在类 + */ + public Class getClazz() { + return clazz; + } + + + /** + * 获得Lambda表达式对象 + * + * @return 获得Lambda表达式对象 + */ + public SerializedLambda getLambda() { + return lambda; } /** * 根据lambda对象的方法签名信息,解析获得实际的参数类型 */ - private Type[] getInstantiatedMethodParamTypes(SerializedLambda lambda, int index) { - final String className = lambda.getInstantiatedMethodType().substring(1, index + 1); + private static Type[] getInstantiatedMethodParamTypes(final String className) { final String[] instantiatedTypeNames = className.split(";"); final Type[] types = new Type[instantiatedTypeNames.length]; for (int i = 0; i < instantiatedTypeNames.length; i++) { @@ -72,32 +161,4 @@ public class LambdaInfo { } return types; } - - public Type[] getInstantiatedMethodParameterTypes() { - return instantiatedMethodParameterTypes; - } - - public Type[] getParameterTypes() { - return parameterTypes; - } - - public Type getReturnType() { - return returnType; - } - - public String getName() { - return name; - } - - public Executable getExecutable() { - return executable; - } - - public Class getClazz() { - return clazz; - } - - public SerializedLambda getLambda() { - return lambda; - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java index 4790332b1..239f845f0 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java @@ -28,27 +28,29 @@ public class LambdaUtil { * 通过对象的方法或类的静态方法引用,获取lambda实现类 * 传入lambda无参数但含有返回值的情况能够匹配到此方法: *
      - *
    • 引用特定对象的实例方法:
      {@code
      -	 * MyTeacher myTeacher = new MyTeacher();
      -	 * Class supplierClass = LambdaUtil.getRealClass(myTeacher::getAge);
      -	 * Assert.assertEquals(MyTeacher.class, supplierClass);
      -	 * }
    • - *
    • 引用静态无参方法:
      {@code
      -	 * Class staticSupplierClass = LambdaUtil.getRealClass(MyTeacher::takeAge);
      -	 * Assert.assertEquals(MyTeacher.class, staticSupplierClass);
      -	 * }
    • + *
    • 引用特定对象的实例方法:
      {@code
      +	 * 			MyTeacher myTeacher = new MyTeacher();
      +	 * 			Class supplierClass = LambdaUtil.getRealClass(myTeacher::getAge);
      +	 * 			Assert.assertEquals(MyTeacher.class, supplierClass);
      +	 * 			}
      + *
    • + *
    • 引用静态无参方法:
      {@code
      +	 * 			Class staticSupplierClass = LambdaUtil.getRealClass(MyTeacher::takeAge);
      +	 * 			Assert.assertEquals(MyTeacher.class, staticSupplierClass);
      +	 * 			}
      + *
    • *
    * 在以下场景无法获取到正确类型 *
    {@code
    -	 * // 枚举测试,只能获取到枚举类型
    -	 * Class> enumSupplierClass = LambdaUtil.getRealClass(LambdaUtil.LambdaKindEnum.REF_NONE::ordinal);
    -	 * Assert.assertEquals(Enum.class, enumSupplierClass);
    -	 * // 调用父类方法,只能获取到父类类型
    -	 * Class> superSupplierClass = LambdaUtil.getRealClass(myTeacher::getId);
    -	 * Assert.assertEquals(Entity.class, superSupplierClass);
    -	 * // 引用父类静态带参方法,只能获取到父类类型
    -	 * Class> staticSuperFunctionClass = LambdaUtil.getRealClass(MyTeacher::takeId);
    -	 * Assert.assertEquals(Entity.class, staticSuperFunctionClass);
    +	 * 		// 枚举测试,只能获取到枚举类型
    +	 * 		Class> enumSupplierClass = LambdaUtil.getRealClass(LambdaUtil.LambdaKindEnum.REF_NONE::ordinal);
    +	 * 		Assert.assertEquals(Enum.class, enumSupplierClass);
    +	 * 		// 调用父类方法,只能获取到父类类型
    +	 * 		Class> superSupplierClass = LambdaUtil.getRealClass(myTeacher::getId);
    +	 * 		Assert.assertEquals(Entity.class, superSupplierClass);
    +	 * 		// 引用父类静态带参方法,只能获取到父类类型
    +	 * 		Class> staticSuperFunctionClass = LambdaUtil.getRealClass(MyTeacher::takeId);
    +	 * 		Assert.assertEquals(Entity.class, staticSuperFunctionClass);
     	 * }
    * * @param func lambda @@ -60,7 +62,10 @@ public class LambdaUtil { @SuppressWarnings("unchecked") public static Class getRealClass(final T func) { final LambdaInfo lambdaInfo = resolve(func); - return (Class) Opt.of(lambdaInfo).map(LambdaInfo::getInstantiatedMethodParameterTypes).filter(types -> types.length != 0).map(types -> types[types.length - 1]).orElseGet(lambdaInfo::getClazz); + return (Class) Opt.of(lambdaInfo) + .map(LambdaInfo::getInstantiatedMethodParameterTypes) + .filter(types -> types.length != 0).map(types -> types[types.length - 1]) + .orElseGet(lambdaInfo::getClazz); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerBiConsumer.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerBiConsumer.java index 6186c7d90..8fad78920 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerBiConsumer.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerBiConsumer.java @@ -10,6 +10,8 @@ import java.util.stream.Stream; /** * SerBiConsumer * + * @param 第一个参数类型 + * @param 第二个参数类型 * @author VampireAchao */ @FunctionalInterface @@ -24,7 +26,8 @@ public interface SerBiConsumer extends BiConsumer, Serializable { */ @SafeVarargs static SerBiConsumer multi(final SerBiConsumer... consumers) { - return Stream.of(consumers).reduce(SerBiConsumer::andThen).orElseGet(() -> (o, q) -> {}); + return Stream.of(consumers).reduce(SerBiConsumer::andThen).orElseGet(() -> (o, q) -> { + }); } /** @@ -79,6 +82,7 @@ public interface SerBiConsumer extends BiConsumer, Serializable { * @return 什么也不做 */ static SerBiConsumer nothing() { - return (l, r) -> {}; + return (l, r) -> { + }; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerFunction.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerFunction.java index 2e2c5b395..66af05eba 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerFunction.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerFunction.java @@ -30,10 +30,10 @@ public interface SerFunction extends Function, Serializable { * @return the function result */ @Override - default R apply(T t) { + default R apply(final T t) { try { return applying(t); - } catch (Exception e) { + } catch (final Exception e) { throw new UtilException(e); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerSupplier.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerSupplier.java index 94d156b8b..7ea302bfb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerSupplier.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerSupplier.java @@ -11,9 +11,10 @@ import java.util.stream.Stream; * * @author VampireAchao * @see Supplier + * @param 返回值类型 */ @FunctionalInterface -public interface SerSupplier extends Supplier, Serializable { +public interface SerSupplier extends Supplier, Serializable { /** * Gets a result. @@ -21,7 +22,7 @@ public interface SerSupplier extends Supplier, Serializable { * @return a result * @throws Exception wrapped checked exceptions */ - T getting() throws Exception; + R getting() throws Exception; /** * Gets a result. @@ -29,7 +30,7 @@ public interface SerSupplier extends Supplier, Serializable { * @return a result */ @Override - default T get() { + default R get() { try { return getting(); } catch (final Exception e) { diff --git a/hutool-core/src/main/java/cn/hutool/core/map/Dict.java b/hutool-core/src/main/java/cn/hutool/core/map/Dict.java index f75b6aa62..4883c6e31 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/Dict.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/Dict.java @@ -7,7 +7,9 @@ import cn.hutool.core.collection.SetUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.exceptions.CloneRuntimeException; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.func.LambdaInfo; import cn.hutool.core.lang.func.LambdaUtil; +import cn.hutool.core.lang.func.SerFunction; import cn.hutool.core.lang.func.SerSupplier; import cn.hutool.core.lang.getter.TypeGetter; @@ -352,6 +354,19 @@ public class Dict extends CustomKeyMap implements TypeGetter 参数类型 + * @param 返回值类型 + * @return 获取表达式对应属性和返回的对象 + */ + public T get(final SerFunction func) { + final LambdaInfo lambdaInfo = LambdaUtil.resolve(func); + return get(lambdaInfo.getFieldName(), lambdaInfo.getReturnType()); + } + /** * 获得特定类型值 * diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/DictTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/DictTest.java index b4ba070f5..8bfcbcb43 100755 --- a/hutool-core/src/test/java/cn/hutool/core/lang/DictTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/DictTest.java @@ -3,14 +3,15 @@ package cn.hutool.core.lang; import cn.hutool.core.builder.GenericBuilder; import cn.hutool.core.date.DateTime; import cn.hutool.core.map.Dict; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; import org.junit.Assert; import org.junit.Test; import java.util.HashMap; import java.util.Map; -import static cn.hutool.core.lang.OptTest.User; - public class DictTest { @Test public void dictTest(){ @@ -70,5 +71,16 @@ public class DictTest { dict.setFields(user::getNickname, user::getUsername); Assert.assertEquals("hutool", dict.get("username")); Assert.assertNull(dict.get("nickname")); + + // get by lambda + Assert.assertEquals("hutool", dict.get(User::getUsername)); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + static class User { + private String username; + private String nickname; } } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/AbstractTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/AbstractTemplate.java deleted file mode 100644 index bbb32b5f7..000000000 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/AbstractTemplate.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.hutool.extra.template; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.StringWriter; -import java.util.Map; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IoUtil; - -/** - * 抽象模板,提供将模板融合后写出到文件、返回字符串等方法 - * - * @author looly - * - */ -public abstract class AbstractTemplate implements Template{ - - @Override - public void render(final Map bindingMap, final File file) { - BufferedOutputStream out = null; - try { - out = FileUtil.getOutputStream(file); - this.render(bindingMap, out); - } finally { - IoUtil.close(out); - } - } - - @Override - public String render(final Map bindingMap) { - final StringWriter writer = new StringWriter(); - render(bindingMap, writer); - return writer.toString(); - } -} diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/Template.java b/hutool-extra/src/main/java/cn/hutool/extra/template/Template.java index e9b92a034..feb6dca32 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/Template.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/Template.java @@ -1,46 +1,63 @@ package cn.hutool.extra.template; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; + +import java.io.BufferedOutputStream; import java.io.File; import java.io.OutputStream; +import java.io.StringWriter; import java.io.Writer; import java.util.Map; /** * 抽象模板接口 - * - * @author looly * + * @author looly */ public interface Template { /** * 将模板与绑定参数融合后输出到Writer - * + * * @param bindingMap 绑定的参数,此Map中的参数会替换模板中的变量 - * @param writer 输出 + * @param writer 输出 */ void render(Map bindingMap, Writer writer); /** * 将模板与绑定参数融合后输出到流 - * + * * @param bindingMap 绑定的参数,此Map中的参数会替换模板中的变量 - * @param out 输出 + * @param out 输出 */ void render(Map bindingMap, OutputStream out); /** * 写出到文件 + * * @param bindingMap 绑定的参数,此Map中的参数会替换模板中的变量 - * @param file 输出到的文件 + * @param file 输出到的文件 */ - void render(Map bindingMap, File file); + default void render(final Map bindingMap, final File file) { + BufferedOutputStream out = null; + try { + out = FileUtil.getOutputStream(file); + this.render(bindingMap, out); + } finally { + IoUtil.close(out); + } + } /** * 将模板与绑定参数融合后返回为字符串 - * + * * @param bindingMap 绑定的参数,此Map中的参数会替换模板中的变量 * @return 融合后的内容 */ - String render(Map bindingMap); + default String render(final Map bindingMap) { + final StringWriter writer = new StringWriter(); + render(bindingMap, writer); + return writer.toString(); + } } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/beetl/BeetlTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/beetl/BeetlTemplate.java index 9b43150b0..0dfb472a8 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/beetl/BeetlTemplate.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/beetl/BeetlTemplate.java @@ -1,6 +1,6 @@ package cn.hutool.extra.template.engine.beetl; -import cn.hutool.extra.template.AbstractTemplate; +import cn.hutool.extra.template.Template; import java.io.OutputStream; import java.io.Serializable; @@ -12,7 +12,7 @@ import java.util.Map; * * @author looly */ -public class BeetlTemplate extends AbstractTemplate implements Serializable{ +public class BeetlTemplate implements Template, Serializable{ private static final long serialVersionUID = -8157926902932567280L; private final org.beetl.core.Template rawTemplate; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/enjoy/EnjoyTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/enjoy/EnjoyTemplate.java index 02448d9fa..97c31d623 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/enjoy/EnjoyTemplate.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/enjoy/EnjoyTemplate.java @@ -1,6 +1,6 @@ package cn.hutool.extra.template.engine.enjoy; -import cn.hutool.extra.template.AbstractTemplate; +import cn.hutool.extra.template.Template; import java.io.OutputStream; import java.io.Serializable; @@ -13,7 +13,7 @@ import java.util.Map; * @author looly * @since 4.1.9 */ -public class EnjoyTemplate extends AbstractTemplate implements Serializable { +public class EnjoyTemplate implements Template, Serializable { private static final long serialVersionUID = 1L; private final com.jfinal.template.Template rawTemplate; @@ -22,7 +22,7 @@ public class EnjoyTemplate extends AbstractTemplate implements Serializable { * 包装Enjoy模板 * * @param EnjoyTemplate Enjoy的模板对象 {@link com.jfinal.template.Template} - * @return {@link EnjoyTemplate} + * @return {@code EnjoyTemplate} */ public static EnjoyTemplate wrap(final com.jfinal.template.Template EnjoyTemplate) { return (null == EnjoyTemplate) ? null : new EnjoyTemplate(EnjoyTemplate); diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerTemplate.java index c1efec5dc..0540ff76b 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerTemplate.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerTemplate.java @@ -2,7 +2,7 @@ package cn.hutool.extra.template.engine.freemarker; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; -import cn.hutool.extra.template.AbstractTemplate; +import cn.hutool.extra.template.Template; import cn.hutool.extra.template.TemplateException; import java.io.IOException; @@ -17,7 +17,7 @@ import java.util.Map; * * @author looly */ -public class FreemarkerTemplate extends AbstractTemplate implements Serializable{ +public class FreemarkerTemplate implements Template, Serializable{ private static final long serialVersionUID = -8157926902932567280L; freemarker.template.Template rawTemplate; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/jetbrick/JetbrickTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/jetbrick/JetbrickTemplate.java index 47157c6bb..31ee80a07 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/jetbrick/JetbrickTemplate.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/jetbrick/JetbrickTemplate.java @@ -2,7 +2,7 @@ package cn.hutool.extra.template.engine.jetbrick; import cn.hutool.core.convert.Convert; import cn.hutool.core.reflect.TypeReference; -import cn.hutool.extra.template.AbstractTemplate; +import cn.hutool.extra.template.Template; import jetbrick.template.JetTemplate; import java.io.OutputStream; @@ -17,7 +17,7 @@ import java.util.Map; * @author looly * @since 5.7.21 */ -public class JetbrickTemplate extends AbstractTemplate implements Serializable{ +public class JetbrickTemplate implements Template, Serializable{ private static final long serialVersionUID = 1L; private final JetTemplate rawTemplate; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/rythm/RythmTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/rythm/RythmTemplate.java index 324ab54c2..b746ea3f2 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/rythm/RythmTemplate.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/rythm/RythmTemplate.java @@ -2,7 +2,7 @@ package cn.hutool.extra.template.engine.rythm; import cn.hutool.core.convert.Convert; import cn.hutool.core.reflect.TypeReference; -import cn.hutool.extra.template.AbstractTemplate; +import cn.hutool.extra.template.Template; import java.io.OutputStream; import java.io.Serializable; @@ -15,7 +15,7 @@ import java.util.Map; * @author looly * */ -public class RythmTemplate extends AbstractTemplate implements Serializable { +public class RythmTemplate implements Template, Serializable { private static final long serialVersionUID = -132774960373894911L; private final org.rythmengine.template.ITemplate rawTemplate; @@ -24,7 +24,7 @@ public class RythmTemplate extends AbstractTemplate implements Serializable { * 包装Rythm模板 * * @param template Rythm的模板对象 {@link org.rythmengine.template.ITemplate} - * @return {@link RythmTemplate} + * @return {@code RythmTemplate} */ public static RythmTemplate wrap(final org.rythmengine.template.ITemplate template) { return (null == template) ? null : new RythmTemplate(template); diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafTemplate.java index 268af8527..3fe35f0e1 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafTemplate.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafTemplate.java @@ -5,7 +5,7 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjUtil; -import cn.hutool.extra.template.AbstractTemplate; +import cn.hutool.extra.template.Template; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; @@ -22,7 +22,7 @@ import java.util.Map; * @author looly * @since 4.1.11 */ -public class ThymeleafTemplate extends AbstractTemplate implements Serializable { +public class ThymeleafTemplate implements Template, Serializable { private static final long serialVersionUID = 781284916568562509L; private final TemplateEngine engine; @@ -35,7 +35,7 @@ public class ThymeleafTemplate extends AbstractTemplate implements Serializable * @param engine Thymeleaf的模板引擎对象 {@link TemplateEngine} * @param template 模板路径或模板内容 * @param charset 编码 - * @return {@link ThymeleafTemplate} + * @return {@code ThymeleafTemplate} */ public static ThymeleafTemplate wrap(final TemplateEngine engine, final String template, final Charset charset) { return (null == engine) ? null : new ThymeleafTemplate(engine, template, charset); diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityTemplate.java index 29110e57a..08db8f269 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityTemplate.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityTemplate.java @@ -3,9 +3,9 @@ package cn.hutool.extra.template.engine.velocity; import cn.hutool.core.convert.Convert; import cn.hutool.core.io.IoUtil; import cn.hutool.core.reflect.TypeReference; -import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.text.StrUtil; -import cn.hutool.extra.template.AbstractTemplate; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.extra.template.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; @@ -20,7 +20,7 @@ import java.util.Map; * @author looly * */ -public class VelocityTemplate extends AbstractTemplate implements Serializable { +public class VelocityTemplate implements Template, Serializable { private static final long serialVersionUID = -132774960373894911L; private final org.apache.velocity.Template rawTemplate; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/wit/WitTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/wit/WitTemplate.java index 54c6c69f3..6f2633f62 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/wit/WitTemplate.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/wit/WitTemplate.java @@ -2,7 +2,6 @@ package cn.hutool.extra.template.engine.wit; import cn.hutool.core.convert.Convert; import cn.hutool.core.reflect.TypeReference; -import cn.hutool.extra.template.AbstractTemplate; import org.febit.wit.Template; import java.io.OutputStream; @@ -15,7 +14,7 @@ import java.util.Map; * * @author looly */ -public class WitTemplate extends AbstractTemplate implements Serializable{ +public class WitTemplate implements cn.hutool.extra.template.Template, Serializable{ private static final long serialVersionUID = 1L; private final Template rawTemplate; diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java index 6179a5d1c..7b95980e4 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -1,6 +1,10 @@ package cn.hutool.json; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.func.LambdaInfo; +import cn.hutool.core.lang.func.LambdaUtil; +import cn.hutool.core.lang.func.SerFunction; +import cn.hutool.core.lang.func.SerSupplier; import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapWrapper; @@ -12,6 +16,7 @@ import java.io.StringWriter; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.function.Predicate; @@ -176,6 +181,18 @@ public class JSONObject extends MapWrapper implements JSON, JSON return this.getOrDefault(key, defaultValue); } + /** + * 根据lambda的方法引用,获取 + * @param func 方法引用 + * @param

    参数类型 + * @param 返回值类型 + * @return 获取表达式对应属性和返回的对象 + */ + public T get(final SerFunction func){ + final LambdaInfo lambdaInfo = LambdaUtil.resolve(func); + return get(lambdaInfo.getFieldName(), lambdaInfo.getReturnType()); + } + /** * PUT 键值对到JSONObject中,在忽略null模式下,如果值为{@code null},将此键移除 * @@ -202,6 +219,22 @@ public class JSONObject extends MapWrapper implements JSON, JSON return this; } + /** + * 通过lambda批量设置值
    + * 实际使用时,可以使用getXXX的方法引用来完成键值对的赋值: + *

    +	 *     User user = GenericBuilder.of(User::new).with(User::setUsername, "hutool").build();
    +	 *     (new JSONObject()).setFields(user::getNickname, user::getUsername);
    +	 * 
    + * + * @param fields lambda,不能为空 + * @return this + */ + public JSONObject setFields(final SerSupplier... fields) { + Arrays.stream(fields).forEach(f -> set(LambdaUtil.getFieldName(f), f.get())); + return this; + } + /** * 一次性Put 键值对,如果key已经存在抛出异常,如果键值中有null值,忽略 * diff --git a/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java b/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java index 1b35526a5..1023bd024 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/AbsSetting.java @@ -3,6 +3,9 @@ package cn.hutool.setting; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.bean.copier.ValueProvider; +import cn.hutool.core.lang.func.LambdaInfo; +import cn.hutool.core.lang.func.LambdaUtil; +import cn.hutool.core.lang.func.SerFunction; import cn.hutool.core.lang.getter.GroupedTypeGetter; import cn.hutool.core.lang.getter.TypeGetter; import cn.hutool.core.reflect.ConstructorUtil; @@ -35,6 +38,19 @@ public abstract class AbsSetting implements TypeGetter, return ObjUtil.defaultIfNull(getObjByGroup(key, DEFAULT_GROUP), defaultValue); } + /** + * 根据lambda的方法引用,获取 + * + * @param func 方法引用 + * @param

    参数类型 + * @param 返回值类型 + * @return 获取表达式对应属性和返回的对象 + */ + public T get(final SerFunction func) { + final LambdaInfo lambdaInfo = LambdaUtil.resolve(func); + return get(lambdaInfo.getFieldName(), lambdaInfo.getReturnType()); + } + /** * 获得字符串类型值,如果字符串为{@code null}或者""返回默认值 * diff --git a/hutool-setting/src/main/java/cn/hutool/setting/Setting.java b/hutool-setting/src/main/java/cn/hutool/setting/Setting.java index d87f4e3ba..853cb86c6 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/Setting.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/Setting.java @@ -10,6 +10,8 @@ import cn.hutool.core.io.watch.SimpleWatcher; import cn.hutool.core.io.watch.WatchMonitor; import cn.hutool.core.io.watch.WatchUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.func.LambdaUtil; +import cn.hutool.core.lang.func.SerSupplier; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharsetUtil; @@ -21,6 +23,7 @@ import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.WatchEvent; +import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; @@ -577,6 +580,22 @@ public class Setting extends AbsSetting implements Map { return this; } + /** + * 通过lambda批量设置值
    + * 实际使用时,可以使用getXXX的方法引用来完成键值对的赋值: + *

    +	 *     User user = GenericBuilder.of(User::new).with(User::setUsername, "hutool").build();
    +	 *     Setting.of().setFields(user::getNickname, user::getUsername);
    +	 * 
    + * + * @param fields lambda,不能为空 + * @return this + */ + public Setting setFields(final SerSupplier... fields) { + Arrays.stream(fields).forEach(f -> set(LambdaUtil.getFieldName(f), f.get())); + return this; + } + /** * 将键值对加入到对应分组中
    * 此方法用于与getXXX统一参数顺序 diff --git a/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java b/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java index 6d2e24cc7..26854fe9a 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java @@ -11,6 +11,10 @@ import cn.hutool.core.io.watch.SimpleWatcher; import cn.hutool.core.io.watch.WatchMonitor; import cn.hutool.core.io.watch.WatchUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.func.LambdaInfo; +import cn.hutool.core.lang.func.LambdaUtil; +import cn.hutool.core.lang.func.SerFunction; +import cn.hutool.core.lang.func.SerSupplier; import cn.hutool.core.lang.getter.TypeGetter; import cn.hutool.core.map.MapUtil; import cn.hutool.core.reflect.ConstructorUtil; @@ -27,6 +31,7 @@ import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.WatchEvent; +import java.util.Arrays; import java.util.Properties; /** @@ -230,6 +235,19 @@ public final class Props extends Properties implements TypeGetter return ObjUtil.defaultIfNull(getProperty(StrUtil.str(key)), defaultValue); } + /** + * 根据lambda的方法引用,获取 + * + * @param func 方法引用 + * @param

    参数类型 + * @param 返回值类型 + * @return 获取表达式对应属性和返回的对象 + */ + public T get(final SerFunction func) { + final LambdaInfo lambdaInfo = LambdaUtil.resolve(func); + return get(lambdaInfo.getFieldName(), lambdaInfo.getReturnType()); + } + /** * 获取并删除键值对,当指定键对应值非空时,返回并删除这个值,后边的键对应的值不再查找 * @@ -353,10 +371,26 @@ public final class Props extends Properties implements TypeGetter * @param key 属性键 * @param value 属性值 */ - public void setProperty(final String key, final Object value) { + public void set(final String key, final Object value) { super.setProperty(key, value.toString()); } + /** + * 通过lambda批量设置值
    + * 实际使用时,可以使用getXXX的方法引用来完成键值对的赋值: + *

    +	 *     User user = GenericBuilder.of(User::new).with(User::setUsername, "hutool").build();
    +	 *     Setting.of().setFields(user::getNickname, user::getUsername);
    +	 * 
    + * + * @param fields lambda,不能为空 + * @return this + */ + public Props setFields(final SerSupplier... fields) { + Arrays.stream(fields).forEach(f -> set(LambdaUtil.getFieldName(f), f.get())); + return this; + } + /** * 持久化当前设置,会覆盖掉之前的设置 * diff --git a/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java b/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java index 8a7262769..0cbac36bb 100644 --- a/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java +++ b/hutool-setting/src/test/java/cn/hutool/setting/PropsTest.java @@ -67,11 +67,11 @@ public class PropsTest { public void toBeanWithNullPrefixTest(){ final Props configProp = new Props(); - configProp.setProperty("createTime", Objects.requireNonNull(DateUtil.parse("2020-01-01"))); - configProp.setProperty("isInit", true); - configProp.setProperty("stairPlan", 1); - configProp.setProperty("stageNum", 2); - configProp.setProperty("version", 3); + configProp.set("createTime", Objects.requireNonNull(DateUtil.parse("2020-01-01"))); + configProp.set("isInit", true); + configProp.set("stairPlan", 1); + configProp.set("stageNum", 2); + configProp.set("version", 3); final SystemConfig systemConfig = configProp.toBean(SystemConfig.class); Assert.assertEquals(DateUtil.parse("2020-01-01"), systemConfig.getCreateTime()); From f8c3b8c1098bcf62ba231ecc6e75050cdf1c3f27 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 23 Sep 2022 23:59:38 +0800 Subject: [PATCH 43/73] fix code --- .../expression/engine/jexl/JexlEngine.java | 3 +++ .../expression/engine/rhino/RhinoEngine.java | 21 +++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/jexl/JexlEngine.java b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/jexl/JexlEngine.java index f4e4ce3da..3c5594752 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/jexl/JexlEngine.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/jexl/JexlEngine.java @@ -17,6 +17,9 @@ public class JexlEngine implements ExpressionEngine { private final org.apache.commons.jexl3.JexlEngine engine; + /** + * 构造 + */ public JexlEngine(){ engine = (new JexlBuilder()).cache(512).strict(true).silent(false).create(); } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/rhino/RhinoEngine.java b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/rhino/RhinoEngine.java index ec52419e9..3f71d1413 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/rhino/RhinoEngine.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/rhino/RhinoEngine.java @@ -19,16 +19,15 @@ public class RhinoEngine implements ExpressionEngine { @Override public Object eval(final String expression, final Map context) { - final Context ctx = Context.enter(); - final Scriptable scope = ctx.initStandardObjects(); - if (MapUtil.isNotEmpty(context)) { - context.forEach((key, value)->{ - // 将java对象转为js对象后放置于JS的作用域中 - ScriptableObject.putProperty(scope, key, Context.javaToJS(value, scope)); - }); - } - final Object result = ctx.evaluateString(scope, expression, "rhino.js", 1, null); - Context.exit(); - return result; + try(final Context ctx = Context.enter()){ + final Scriptable scope = ctx.initStandardObjects(); + if (MapUtil.isNotEmpty(context)) { + context.forEach((key, value)->{ + // 将java对象转为js对象后放置于JS的作用域中 + ScriptableObject.putProperty(scope, key, Context.javaToJS(value, scope)); + }); + } + return ctx.evaluateString(scope, expression, "rhino.js", 1, null); + } // auto close } } From 44786ba76cb3918668a3c6a82b2d5dcf5f099e82 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 24 Sep 2022 00:05:04 +0800 Subject: [PATCH 44/73] fix template --- .gitee/PULL_REQUEST_TEMPLATE.zh-CN.md | 6 +++--- .github/PULL_REQUEST_TEMPLATE.md | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md index e80f21900..848958d8d 100644 --- a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md +++ b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md @@ -1,15 +1,15 @@ -### 说明 +### 📣说明 1. 请确认你提交的PR是到'v6-dev'分支,否则我会手动修改代码并关闭PR。 2. 请确认没有更改代码风格(如tab缩进) 3. 新特性添加请确认注释完备,如有必要,请在src/test/java下添加Junit测试用例 -### 修改描述(包括说明bug修复或者添加新特性) +### 🔧修改描述(包括说明bug修复或者添加新特性) 1. [bug修复] balabala…… 2. [新特性] balabala…… -### 提交前自测 +### 😊提交前自测 > 请在提交前自测确保代码没有问题,提交新代码应包含:测试用例、通过(mvn javadoc:javadoc)检验详细注释。 1. 本地如有多个JDK版本,可以设置临时JDk版本,如:`export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_331.jdk/Contents/Home`,具体替换为本地jdk目录 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6a5dae969..2ef6a3097 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,10 +1,19 @@ -#### 说明 +### 📣说明 1. 请确认你提交的PR是到'v5-dev'分支,否则我会手动修改代码并关闭PR。 2. 请确认没有更改代码风格(如tab缩进) 3. 新特性添加请确认注释完备,如有必要,请在src/test/java下添加Junit测试用例 -### 修改描述(包括说明bug修复或者添加新特性) +### 🔧修改描述(包括说明bug修复或者添加新特性) 1. [bug修复] balabala…… -2. [新特性] balabala…… \ No newline at end of file +2. [新特性] balabala…… + +### 😊提交前自测 +> 请在提交前自测确保代码没有问题,提交新代码应包含:测试用例、通过(mvn javadoc:javadoc)检验详细注释。 + +1. 本地如有多个JDK版本,可以设置临时JDk版本,如:`export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_331.jdk/Contents/Home`,具体替换为本地jdk目录 +2. 确保本地测试使用JDK8最新版本,`echo $JAVA_HOME`、`mvn -v`、`java -version`均正确。 +3. 执行打包生成文档,使用`mvn clean package -Dmaven.test.skip=true -U`,并确认通过,会自动执行打包、生成文档 +4. 如需要单独执行文档生成,执行:`mvn javadoc:javadoc `,并确认通过 +5. 如需要单独执行测试用例,执行:`mvn clean test`,并确认通过 \ No newline at end of file From 782037c4de32b05f14e35a81486cfe5538aeb157 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 24 Sep 2022 00:52:31 +0800 Subject: [PATCH 45/73] fix bug --- .../java/cn/hutool/core/util/EnumUtil.java | 8 ++++---- .../cn/hutool/poi/excel/ExcelDateUtil.java | 14 +++++++++++--- .../excel/cell/values/NumericCellValue.java | 12 +++++------- .../cn/hutool/poi/excel/IssueI5Q1TWTest.java | 18 +++++++++--------- hutool-poi/src/test/resources/I5Q1TW.xlsx | Bin 0 -> 9230 bytes 5 files changed, 29 insertions(+), 23 deletions(-) create mode 100644 hutool-poi/src/test/resources/I5Q1TW.xlsx diff --git a/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java index 1e7607b5b..6e85d2095 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/EnumUtil.java @@ -325,15 +325,15 @@ public class EnumUtil { } /** - * 判断某个值是存在枚举中 + * 判断指定名称的枚举是否存在 * * @param 枚举类型 * @param enumClass 枚举类 - * @param val 需要查找的值 + * @param name 需要查找的枚举名 * @return 是否存在 */ - public static > boolean contains(final Class enumClass, final String val) { - return EnumUtil.getEnumMap(enumClass).containsKey(val); + public static > boolean contains(final Class enumClass, final String name) { + return getEnumMap(enumClass).containsKey(name); } /** diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java index ae06a1f4f..8f53150ab 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java @@ -19,23 +19,31 @@ public class ExcelDateUtil { */ private static final int[] customFormats = new int[]{28, 30, 31, 32, 33, 55, 56, 57, 58}; - public static boolean isDateFormat(final Cell cell){ + /** + * 是否日期格式 + * + * @param cell 单元格 + * @return 是否日期格式 + */ + public static boolean isDateFormat(final Cell cell) { return isDateFormat(cell, null); } /** * 判断是否日期格式 - * @param cell 单元格 + * + * @param cell 单元格 * @param cfEvaluator {@link ConditionalFormattingEvaluator} * @return 是否日期格式 */ - public static boolean isDateFormat(final Cell cell, final ConditionalFormattingEvaluator cfEvaluator){ + public static boolean isDateFormat(final Cell cell, final ConditionalFormattingEvaluator cfEvaluator) { final ExcelNumberFormat nf = ExcelNumberFormat.from(cell, cfEvaluator); return isDateFormat(nf); } /** * 判断是否日期格式 + * * @param numFmt {@link ExcelNumberFormat} * @return 是否日期格式 */ diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/values/NumericCellValue.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/values/NumericCellValue.java index ccab77866..b5ae0a993 100755 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/values/NumericCellValue.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/values/NumericCellValue.java @@ -1,6 +1,5 @@ package cn.hutool.poi.excel.cell.values; -import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.poi.excel.ExcelDateUtil; import cn.hutool.poi.excel.cell.CellValue; @@ -8,7 +7,7 @@ import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.util.NumberToTextConverter; -import java.util.Date; +import java.time.LocalDateTime; /** * 数字类型单元格值
    @@ -38,13 +37,12 @@ public class NumericCellValue implements CellValue { if (null != style) { // 判断是否为日期 if (ExcelDateUtil.isDateFormat(cell)) { + final LocalDateTime date = cell.getLocalDateTimeCellValue(); // 1899年写入会导致数据错乱,读取到1899年证明这个单元格的信息不关注年月日 - final Date dateCellValue = cell.getDateCellValue(); - if ("1899".equals(DateUtil.format(dateCellValue, "yyyy"))) { - return DateUtil.format(dateCellValue, style.getDataFormatString()); + if(1899 == date.getYear()){ + return date.toLocalTime(); } - // 使用Hutool的DateTime包装 - return DateUtil.date(dateCellValue); + return date; } final String format = style.getDataFormatString(); diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/IssueI5Q1TWTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/IssueI5Q1TWTest.java index 7e79cc46d..ced81e931 100755 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/IssueI5Q1TWTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/IssueI5Q1TWTest.java @@ -1,18 +1,18 @@ package cn.hutool.poi.excel; -import cn.hutool.core.lang.Console; -import org.junit.Ignore; +import org.junit.Assert; import org.junit.Test; -import java.util.List; - public class IssueI5Q1TWTest { @Test - @Ignore - public void readTest(){ - final ExcelReader reader = ExcelUtil.getReader("d:/test/I5Q1TW.xlsx"); - final List> read = reader.read(); - Console.log(reader.readCellValue(0, 0)); + public void readTest() { + final ExcelReader reader = ExcelUtil.getReader("I5Q1TW.xlsx"); + + // 自定义时间格式1 + Assert.assertEquals("18:56", reader.readCellValue(0, 0).toString()); + + // 自定义时间格式2 + Assert.assertEquals("18:56", reader.readCellValue(1, 0).toString()); } } diff --git a/hutool-poi/src/test/resources/I5Q1TW.xlsx b/hutool-poi/src/test/resources/I5Q1TW.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7507bfe64f3aa5d5faf287c23ea825341ccc065f GIT binary patch literal 9230 zcmeHNWm{a!vL4)ha0~8EaCdk2;O@aKxCfU62oAv|Xo72ScS5k>?tUj*p6t!d`32|n zhqYEeGgUL){Z`dmRZB@00ul&-2EYOU01^OHyw{}>7y#e{2>@UKV8L}o9qe7r>|G7j zJRQwk^cg+uY+vL;f>UP$z(L>t-}o=yfwH7Q`%Y$5@vG!pl=ud9v(1`OH47oDYy_#DpWDnDu)r#_g|<^l|S<^x>{%l z3ACr|9O68J%m(hCOZeAO%7yt2q42WbT+efVPgDw{hvYp7hB;!mR^=1 zuh_+m78itnAIYq*$Y_%KBZTe#RGF?)}liIE2Ep2IIagOZQ z6*7s*6R~R4QASNXIE(^qU2#Vu zv3i$UK`3Lpj}Yc^$gelTw9ChqRU8+Mjn-+w!D@+i7L2(E`_P)14q+-K9vN)|6qB;!Il>LHB~Ue?$j5m=z5TLVlYXDv|MOy8WV zci0TZEEb3Dkz~HM?lI>3NUVm=P|o{*Gl-HbAQ;`r{Tf z5Z9AnWEKkBH2uv!p0@0K2+;#dDLz&TDF@3oB%S z&<&kH0T%r(e!5lvgygoqQxv1QM^-#&o0kS~B%U9{&Mub-*!c{rqrcV7yp+;@ByFlt z3yqGJdMTflD;<1WwV~@Z2T;$YmBbu;vFp(q6aR8)(UZgotgdYchzX_aI)nhFv8eo1 zQjWLpG|SYAnnBu$tSBnkAEJ{P?3d6SWyD*i<(z$De1xnz zdKAidSpu~u@w#tYg9yGnRl;{PGT4F46nbnc>#fEjrRykqa-gE4;Bnme;X}4 zJC?6&A#B$R4k?~)ePXQwtUf%R_~X$2`n+++9}rFKRz3tV`8c|W zy+m@djbG2Oqn~)Q`S#TAbVQeCN3%<4$WIUKSJ+z$+#TMMaW@4BrC3Q}DH`^LU6ONi$YN$CC_cm4wH+57Klq zG3#KHdU(xL`G@GC46-yv#yv7YaNgk%JrFZTblP_i@=>ym?>=vq9Kx2`hz%7ayqXoE z87IwTh<@!;F?PkV<04#-e8ecw5+uj#SD0VmIJ3wqCS`v2Zu9_UKF-OBJoBy%Ht{?? zsLmGoIC$4UQ^ncc^tEEux8$l0v>Dq}SNvV|apVuBMWvs`RahdXhRd!)_}0z>=7<7_;@3!Ed> z*4lJpS^&JX(KV`1*&KEd4{K6j6owyk4p{Bh?G2olQg~br&^i;CQa%ZbyhVMYDTFcI_R3R=p-O5qC9$HxeBemN>rli znT%~R;<;SXzHNfA456^KU2=55Ju5E+zYBtzk$Ik>xkcUwMD+tmWjiUQI)O0?Az#>{ zpRVAqA7hUdhVK+Y6t8660L+k*$`s*i>H~wbj6PXW6(`0?h$|kc?H{(aT_0(pbLWh2 z=G%Wal|RaXv~UnciFlilRgB>jm|H;}JqJxlBYzkg%L-J2)-uuD`bVI|&M(;FfJx>q$u+DF1#@(|jWgw$k*`zV@iYA_uS)W$x+4_MuKa#XRyZu-=x+ zCb8af37LO_!>&3>;HTC9^5vvE&sY~QGQaF}QZLN1w~?Xrt*edo-X zZr%!+hK!$jt&$Y5$Xkn>Ze&5O-+X7Y1p(ji@q5iHky?x$JbWy8UjA}vNW+tG^AX%! zLhRf0nlm&%dc81G#_z&?7gHZ}m)i`)y+hD2d2L^Q&bg)AhY#AZ(!WR_?t8D`D|p;> z*xLrKR2_rQ4zv1V=~@-Qp589y!q_~TJ$rZ&1YY{)R5t3!uXd#v*JIe&KCO>2Rsj`NE&IyhA{(Fj@%1N&N$q>Fbxmh z|ija0(PWiQOH8GlAtgi*mKp*MUafg5zEm3;B)Y({z zAlJ1*_si|gqCbe&-rO~OFyOyqJUS=M+Ph9|^LsdbD`>by)T;x%+H*B(`1p9=gR*je zF~}BmWgpth<0FPXl(~4l)YONL^Dab?$il&bB@&H=UJ0?4p#lb#i_pV6q!?+o%N&;2 zG@FUzd&g;f#|8OFN}!fkD<&26aT?2lN%~7bgQ=lTu;iet{Slw;ZlgDB=KO7}k~O(U zm0my<`ujoZUg+V^zyk1Lr^pbp57nyC40+yC;b^latY2{~*jD+-6;RM@q$Esjfhtz6 zQt17I0}`kzcHKX&-%OfJaqJ2Ru*Dziys#z_?3{vK2h)L1n$wF_61fN4tD{m~BbwUf8|G+0bB0-^EPCtZ!#NTPvgFOr?+f5n(k5^1dr$~iKOFvqV96{Bf zg(z_d_Y|3sO@0V0gdx_MJlOStvbJ}>7vT9e9DZTP^CkP+XU8Yu;ln&LFYGRx8h#7k zgnh+?gU2HZ@7d2j7b5!BZ2fLc0-B{4rd!6o64d-?bdhfxbt+xb;tNGB)$rl!-Y?mH z!(!3H(uIKF9F41SVx?>)Cl!bo2gka2S$C0f)_IY^i_rV3yz<>NC63{7xf|l(MwaBl&Ew7==)i!XNOQY=@h){U%D0)^}nF|}B^tHyR4-+VZFc!eKAoi)I>*$3F$AK1{dDs+cR z+{Fa!g}sJKO1GD-;0>daOif+DH(hvyuz8()l(q8)}Wn#Wd2tm#|$Rejc~a}Lz1q*GrleM@+I1O0_O*O@@8`a!KEvhj99rS#}=V+|EG zlj@c4oc$;7R|U)4$aH>fvn8MMsx)`Plxqd|C521*eRg>);P>6}s0JdQO0Hi;ImW!*W zt(nVD?v<}T9J|PY+KRo+iz-&BBU7_cr!Q^w#Q+SfMmS&@9BhKfGNLBpSTcJ%W+}J9 z;FO&Ig6Mpr2ri*-TPeY=iKhABhjC(8xD&U7I~968UPg1P<(Gb9e(P8S=_6z> zK%+4z;mgT~>$o^hNDH2kdA@SZqw@x96w}0Hn%i>SGF7m25&_@nBY|Q$>8hR6J(J20 z$8j6gzi~_{&KxSRQ_684DCFXcRC+os3&t}vFrL!flu3;%nqBdT7kqO19Cr$HejfVe z%grUP9I}x`${3=Fti{A$LWfI=nobOy&|?mK6sJs^dXqOec>92rne-V(a}hZCn=?(z z9Hg2texZ^?YFh2elaniV;-~9LD|I#J>Z5`j4A%#aVrk@QcaaHRE_b%0TrYsjgz~(~ zq>#ncKIOQmACEgy+`34H*$P|@B;GV@o^xaNs!u~Di3}9m^yI-g(bzYfW|U43Qz4!( z?V6dwU|fNzWwSaDQ`t_8ZYpv6ta9b#rZV zUth9$HdKdV-Q!zx0t{mpHo`58R<2j;`G|- z7gd{lW*KG}x+~%&nUqQr)Lp6emrq!Fiq4SeZWKZ#%Twre70zvH5eK<-$d^cz)6IbaJiJD?e=_zSV4to;k&)-#nxPM*@mP zNwn{Bh*pV)H&AIuN~UJ{aViRV5BU-)JQO*7_rB>y`C=(!@y(VeqJm zt?wWd6l5a$;^cvXeZ?y}^Z;oVC;(BH5G_^6|L1!ao?gVbVA0^=|>SZWICm z_zx>{q$5C@H3=@x3~zzMrmY{3jRXh+$fzV@Z=J(&KCF&ip^>`{6-TBO8%>Q-o_}m} z{BgmA$3FD^J}BOP@;3ZIEz(P{z=g3Br|Issuw9k>4p4l@JNBUDZXc(%d2whBJ?hrk z{A}^-j%<-UWmKYcIp@7P%|$FM;>t8vo6lGBS?m4cCGPuPIE|_fO@o{f7e>-B))^%u zdP$b*5vINj@O3jCx^tvk&t3Eua1D$jD!Q4$3hmMy-0S#R)s)FyulT*EVz@0O}bMPv4ZikegEkWA*9&iX6M2mjhl#43xlnd3w3+U0$!!eu4b zflTwFm_3ud*@N@h5W!Ll&FE=p8!5qQ)usVMJj+c7<;x^Nm~VonA9mJZ4JNeT?Q;^{ zMF(M(6U8A=yYpw94#rRboxc?*)kg!BflM7tl$;$LU6@Q9oX!4f-u1GHAIdFxQOSafegVasCpSVH~4^%Yh<3D3HT_sE0Si2UScYsDAEu|hRg zQF7RLm;^fI0lUzwsANIOtZF%U4H`Jy-S%uVKhOBnQ0IbG_Y^8uA zK$9+aB{mGMFxNGSop;*qQ@Tsck0bQ~dCVEBc=Q-UtV<9N=H$6#D#vK^KHJs+*w~yv zy!@AGkdXe~4BHF$+|1M%7WxYnPMNVzMYbI%Yun%6JG0l@;eR?o?b@WezIgS(u67|i ze-sHZpxQw*+g>(tqw}%k>`?GEfk^ z`(?4c6@r;@LT-;X0-oEO@#ONt$>uj(Nb}-;e+P;pAz{ zp+lP3+Lz0ouyDDTf$SBrFUuigdDnm;ZE%qt5mrx)2AT{{yWiqnU}K@U#A5o8%_fJEz{MA= z=EW66Vm*aX%A2r^5uOsb$NS{XpQPc>+Bz6G1K>Zs74i4^{eAzHR#5HhS%2%f@V}b^zeE9mMi6`W&n<%IdY%`Le`%TnWjX(; zl>A)F^Mc(kEhWgmE#Ey?@H~0?rN9tGcR+vRS1R>f^f@#9CE5b2hW~p7zvYR~6+S0g zzZACN{-N+0&H63vdam@}(fgN50H6&Y0Qi5g{JHqQ{q8@-#fbhP{+Ab4l7#{x=;zA> O2!IU`T>z5&oc$jvi^G!u literal 0 HcmV?d00001 From a4e98c688570676d715bad38a6691941d8a582c3 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 24 Sep 2022 01:11:45 +0800 Subject: [PATCH 46/73] fix doc --- .../main/java/cn/hutool/core/regex/RegexPool.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/regex/RegexPool.java b/hutool-core/src/main/java/cn/hutool/core/regex/RegexPool.java index ead0757ad..42604b5cb 100755 --- a/hutool-core/src/main/java/cn/hutool/core/regex/RegexPool.java +++ b/hutool-core/src/main/java/cn/hutool/core/regex/RegexPool.java @@ -53,29 +53,23 @@ public interface RegexPool { */ String EMAIL = "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)])"; /** - * 移动电话 + * 移动电话
    + * eg: 中国大陆: +86 180 4953 1399,2位区域码标示+13位数字 */ String MOBILE = "(?:0|86|\\+86)?1[3-9]\\d{9}"; /** * 中国香港移动电话 * eg: 中国香港: +852 5100 4810, 三位区域码+10位数字, 中国香港手机号码8位数 - * eg: 中国大陆: +86 180 4953 1399,2位区域码标示+13位数字 - * 中国大陆 +86 Mainland China - * 中国香港 +852 Hong Kong - * 中国澳门 +853 Macao - * 中国台湾 +886 Taiwan */ String MOBILE_HK = "(?:0|852|\\+852)?\\d{8}"; /** * 中国台湾移动电话 * eg: 中国台湾: +886 09 60 000000, 三位区域码+号码以数字09开头 + 8位数字, 中国台湾手机号码10位数 - * 中国台湾 +886 Taiwan 国际域名缩写:TW */ String MOBILE_TW = "(?:0|886|\\+886)?(?:|-)09\\d{8}"; /** * 中国澳门移动电话 - * eg: 中国台湾: +853 68 00000, 三位区域码 +号码以数字6开头 + 7位数字, 中国台湾手机号码8位数 - * 中国澳门 +853 Macao 国际域名缩写:MO + * eg: 中国澳门: +853 68 00000, 三位区域码 +号码以数字6开头 + 7位数字, 中国台湾手机号码8位数 */ String MOBILE_MO = "(?:0|853|\\+853)?(?:|-)6\\d{7}"; /** From 1030f22757cf7caa0c31144cd979eb279987eb73 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 24 Sep 2022 11:54:13 +0800 Subject: [PATCH 47/73] fix code --- .../java/cn/hutool/db/dialect/impl/OracleDialect.java | 4 ++-- .../main/java/cn/hutool/db/handler/ResultSetUtil.java | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/hutool-db/src/main/java/cn/hutool/db/dialect/impl/OracleDialect.java b/hutool-db/src/main/java/cn/hutool/db/dialect/impl/OracleDialect.java index e66a05653..09e7cc9d8 100644 --- a/hutool-db/src/main/java/cn/hutool/db/dialect/impl/OracleDialect.java +++ b/hutool-db/src/main/java/cn/hutool/db/dialect/impl/OracleDialect.java @@ -35,8 +35,8 @@ public class OracleDialect extends AnsiSqlDialect { return find .insertPreFragment("SELECT * FROM ( SELECT row_.*, rownum rownum_ from ( ") .append(" ) row_ where rownum <= ").append(startEnd[1])// - .append(") table_alias")// - .append(" where table_alias.rownum_ > ").append(startEnd[0]);// + .append(") table_alias_")// + .append(" where table_alias_.rownum_ > ").append(startEnd[0]);// } @Override diff --git a/hutool-db/src/main/java/cn/hutool/db/handler/ResultSetUtil.java b/hutool-db/src/main/java/cn/hutool/db/handler/ResultSetUtil.java index 099e53aa1..37e979795 100644 --- a/hutool-db/src/main/java/cn/hutool/db/handler/ResultSetUtil.java +++ b/hutool-db/src/main/java/cn/hutool/db/handler/ResultSetUtil.java @@ -150,9 +150,16 @@ public class ResultSetUtil { */ public static T toEntity(final T row, final int columnCount, final ResultSetMetaData meta, final ResultSet rs, final boolean withMetaInfo) throws SQLException { int type; + String columnLabel; for (int i = 1; i <= columnCount; i++) { type = meta.getColumnType(i); - row.put(meta.getColumnLabel(i), getColumnValue(rs, i, type, null)); + columnLabel = meta.getColumnLabel(i); + if("rownum_".equalsIgnoreCase(columnLabel)){ + // issue#2618@Github + // 分页时会查出rownum字段,此处忽略掉读取 + continue; + } + row.put(columnLabel, getColumnValue(rs, i, type, null)); } if (withMetaInfo) { try { From df84bca82882a3bdb2f56b66e15062cc4e5ba24f Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Sat, 24 Sep 2022 13:54:53 +0800 Subject: [PATCH 48/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=97=A0=E5=90=91=E5=9B=BE=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E7=9A=84Map=E9=9B=86=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/ResolvedAnnotationMapping.java | 12 +- .../java/cn/hutool/core/map/multi/Graph.java | 141 ++++++++++++++++ .../java/cn/hutool/core/map/GraphTest.java | 155 ++++++++++++++++++ 3 files changed, 301 insertions(+), 7 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/map/multi/Graph.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/map/GraphTest.java diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/ResolvedAnnotationMapping.java b/hutool-core/src/main/java/cn/hutool/core/annotation/ResolvedAnnotationMapping.java index 943b783cb..afdc9c543 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/ResolvedAnnotationMapping.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/ResolvedAnnotationMapping.java @@ -2,8 +2,7 @@ package cn.hutool.core.annotation; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.map.multi.MultiValueMap; -import cn.hutool.core.map.multi.SetValueMap; +import cn.hutool.core.map.multi.Graph; import cn.hutool.core.reflect.ClassUtil; import cn.hutool.core.reflect.MethodUtil; import cn.hutool.core.text.CharSequenceUtil; @@ -479,8 +478,8 @@ public class ResolvedAnnotationMapping implements AnnotationMapping private void resolveAliasAttributes() { final Map attributeIndexes = new HashMap<>(attributes.length); + final Graph methodGraph = new Graph<>(); // 解析被作为别名的关联属性,根据节点关系构建邻接表 - final MultiValueMap aliasedMethods = new SetValueMap<>(); for (int i = 0; i < attributes.length; i++) { // 获取属性上的@Alias注解 final Method attribute = attributes[i]; @@ -492,15 +491,14 @@ public class ResolvedAnnotationMapping implements AnnotationMapping // 获取别名属性 final Method aliasAttribute = getAliasAttribute(attribute, attributeAnnotation); Objects.requireNonNull(aliasAttribute); - aliasedMethods.putValue(aliasAttribute, attribute); - aliasedMethods.putValue(attribute, aliasAttribute); + methodGraph.putEdge(aliasAttribute, attribute); } // 按广度优先遍历邻接表,将属于同一张图上的节点分为一组,并为其建立AliasSet final Set accessed = new HashSet<>(attributes.length); final Set group = new LinkedHashSet<>(); final Deque deque = new LinkedList<>(); - for (final Method target : aliasedMethods.keySet()) { + for (final Method target : methodGraph.keySet()) { group.clear(); deque.addLast(target); while (!deque.isEmpty()) { @@ -512,7 +510,7 @@ public class ResolvedAnnotationMapping implements AnnotationMapping accessed.add(curr); // 将其添加到关系组 group.add(curr); - Collection aliases = aliasedMethods.get(curr); + final Collection aliases = methodGraph.getAdjacentPoints(curr); if (CollUtil.isNotEmpty(aliases)) { deque.addAll(aliases); } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/multi/Graph.java b/hutool-core/src/main/java/cn/hutool/core/map/multi/Graph.java new file mode 100644 index 000000000..681b6b6f0 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/map/multi/Graph.java @@ -0,0 +1,141 @@ +package cn.hutool.core.map.multi; + +import cn.hutool.core.collection.CollUtil; + +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; + +/** + * 支持处理无向图结构的{@link Map},本质上是基于{@link SetValueMap}实现的邻接表 + * + * @param 节点类型 + * @author huangchengxing + * @since 6.0.0 + */ +public class Graph extends SetValueMap { + + /** + * 添加边 + * + * @param target1 节点 + * @param target2 节点 + */ + public void putEdge(final T target1, final T target2) { + this.putValue(target1, target2); + this.putValue(target2, target1); + } + + /** + * 是否存在边 + * + * @param target1 节点 + * @param target2 节点 + * @return 是否 + */ + public boolean containsEdge(final T target1, final T target2) { + return this.getValues(target1).contains(target2) + && this.getValues(target2).contains(target1); + } + + /** + * 移除边 + * + * @param target1 节点 + * @param target2 节点 + */ + public void removeEdge(final T target1, final T target2) { + this.removeValue(target1, target2); + this.removeValue(target2, target1); + } + + /** + * 移除节点,并删除该节点与其他节点之间连成的边 + * + * @param target 目标对象 + */ + public void removePoint(final T target) { + final Collection associatedPoints = this.remove(target); + if (CollUtil.isNotEmpty(associatedPoints)) { + associatedPoints.forEach(p -> this.removeValue(p, target)); + } + } + + /** + * 两节点是否存在直接或间接的关联 + * + * @param target1 节点 + * @param target2 节点 + * @return 两节点是否存在关联 + */ + public boolean containsAssociation(final T target1, final T target2) { + if (!this.containsKey(target1) || !this.containsKey(target2)) { + return false; + } + final AtomicBoolean flag = new AtomicBoolean(false); + visitAssociatedPoints(target1, t -> { + if (Objects.equals(t, target2)) { + flag.set(true); + return true; + } + return false; + }); + return flag.get(); + } + + /** + * 按广度优先,获得节点的所有直接或间接关联的节点,节点默认按添加顺序排序 + * + * @param target 节点 + * @param includeTarget 是否包含查询节点 + * @return 节点的所有关联节点 + */ + public Collection getAssociatedPoints(final T target, final boolean includeTarget) { + final Set points = visitAssociatedPoints(target, t -> false); + if (!includeTarget) { + points.remove(target); + } + return points; + } + + /** + * 获取节点的邻接节点 + * + * @param target 节点 + * @return 邻接节点 + */ + public Collection getAdjacentPoints(final T target) { + return this.getValues(target); + } + + /** + * 按广度优先,访问节点的所有关联节点 + */ + private Set visitAssociatedPoints(final T key, final Predicate breaker) { + if (!this.containsKey(key)) { + return Collections.emptySet(); + } + final Set accessed = new HashSet<>(); + final Deque deque = new LinkedList<>(); + deque.add(key); + while (!deque.isEmpty()) { + // 访问节点 + final T t = deque.removeFirst(); + if (accessed.contains(t)) { + continue; + } + accessed.add(t); + // 若符合条件则中断循环 + if (breaker.test(t)) { + break; + } + // 获取邻接节点 + final Collection neighbours = this.getValues(t); + if (!neighbours.isEmpty()) { + deque.addAll(neighbours); + } + } + return accessed; + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/map/GraphTest.java b/hutool-core/src/test/java/cn/hutool/core/map/GraphTest.java new file mode 100644 index 000000000..ae031c59f --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/map/GraphTest.java @@ -0,0 +1,155 @@ +package cn.hutool.core.map; + +import cn.hutool.core.map.multi.Graph; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * test for {@link Graph} + */ +public class GraphTest { + + @Test + public void testPutEdge() { + Graph graph = new Graph<>(); + graph.putEdge(0, 1); + graph.putEdge(1, 2); + graph.putEdge(2, 0); + + Assert.assertEquals(asSet(1, 2), graph.getValues(0)); + Assert.assertEquals(asSet(0, 2), graph.getValues(1)); + Assert.assertEquals(asSet(0, 1), graph.getValues(2)); + } + + @Test + public void testContainsEdge() { + // 0 -- 1 + // | | + // 3 -- 2 + Graph graph = new Graph<>(); + graph.putEdge(0, 1); + graph.putEdge(1, 2); + graph.putEdge(2, 3); + graph.putEdge(3, 0); + + Assert.assertTrue(graph.containsEdge(0, 1)); + Assert.assertTrue(graph.containsEdge(1, 0)); + + Assert.assertTrue(graph.containsEdge(1, 2)); + Assert.assertTrue(graph.containsEdge(2, 1)); + + Assert.assertTrue(graph.containsEdge(2, 3)); + Assert.assertTrue(graph.containsEdge(3, 2)); + + Assert.assertTrue(graph.containsEdge(3, 0)); + Assert.assertTrue(graph.containsEdge(0, 3)); + + Assert.assertFalse(graph.containsEdge(1, 3)); + } + + @Test + public void removeEdge() { + Graph graph = new Graph<>(); + graph.putEdge(0, 1); + Assert.assertTrue(graph.containsEdge(0, 1)); + + graph.removeEdge(0, 1); + Assert.assertFalse(graph.containsEdge(0, 1)); + } + + @Test + public void testContainsAssociation() { + // 0 -- 1 + // | | + // 3 -- 2 + Graph graph = new Graph<>(); + graph.putEdge(0, 1); + graph.putEdge(1, 2); + graph.putEdge(2, 3); + graph.putEdge(3, 0); + + Assert.assertTrue(graph.containsAssociation(0, 2)); + Assert.assertTrue(graph.containsAssociation(2, 0)); + + Assert.assertTrue(graph.containsAssociation(1, 3)); + Assert.assertTrue(graph.containsAssociation(3, 1)); + + Assert.assertFalse(graph.containsAssociation(-1, 1)); + Assert.assertFalse(graph.containsAssociation(1, -1)); + } + + @Test + public void testGetAssociationPoints() { + // 0 -- 1 + // | | + // 3 -- 2 + Graph graph = new Graph<>(); + graph.putEdge(0, 1); + graph.putEdge(1, 2); + graph.putEdge(2, 3); + graph.putEdge(3, 0); + + Assert.assertEquals(asSet(0, 1, 2, 3), graph.getAssociatedPoints(0, true)); + Assert.assertEquals(asSet(1, 2, 3), graph.getAssociatedPoints(0, false)); + + Assert.assertEquals(asSet(1, 2, 3, 0), graph.getAssociatedPoints(1, true)); + Assert.assertEquals(asSet(2, 3, 0), graph.getAssociatedPoints(1, false)); + + Assert.assertEquals(asSet(2, 3, 0, 1), graph.getAssociatedPoints(2, true)); + Assert.assertEquals(asSet(3, 0, 1), graph.getAssociatedPoints(2, false)); + + Assert.assertEquals(asSet(3, 0, 1, 2), graph.getAssociatedPoints(3, true)); + Assert.assertEquals(asSet(0, 1, 2), graph.getAssociatedPoints(3, false)); + + Assert.assertTrue(graph.getAssociatedPoints(-1, false).isEmpty()); + } + + @Test + public void testGetAdjacentPoints() { + // 0 -- 1 + // | | + // 3 -- 2 + Graph graph = new Graph<>(); + graph.putEdge(0, 1); + graph.putEdge(1, 2); + graph.putEdge(2, 3); + graph.putEdge(3, 0); + + Assert.assertEquals(asSet(1, 3), graph.getAdjacentPoints(0)); + Assert.assertEquals(asSet(2, 0), graph.getAdjacentPoints(1)); + Assert.assertEquals(asSet(1, 3), graph.getAdjacentPoints(2)); + Assert.assertEquals(asSet(2, 0), graph.getAdjacentPoints(3)); + } + + @Test + public void testRemovePoint() { + // 0 -- 1 + // | | + // 3 -- 2 + Graph graph = new Graph<>(); + graph.putEdge(0, 1); + graph.putEdge(1, 2); + graph.putEdge(2, 3); + graph.putEdge(3, 0); + + // 0 + // | + // 3 -- 2 + graph.removePoint(1); + + Assert.assertEquals(asSet(3), graph.getAdjacentPoints(0)); + Assert.assertTrue(graph.getAdjacentPoints(1).isEmpty()); + Assert.assertEquals(asSet(3), graph.getAdjacentPoints(2)); + Assert.assertEquals(asSet(2, 0), graph.getAdjacentPoints(3)); + } + + + private static Set asSet(T... ts) { + return new LinkedHashSet<>(Arrays.asList(ts)); + } + +} From 0f3c6587467cc6118730ad30ca0cc5c0bd3702d5 Mon Sep 17 00:00:00 2001 From: TanShengyuan <2635891552@qq.com> Date: Sat, 24 Sep 2022 17:07:56 +0800 Subject: [PATCH 49/73] :trollface: --- .../cn/hutool/core/stream/CollectorUtil.java | 21 ++++++++ .../hutool/core/stream/CollectorUtilTest.java | 52 ++++++++++++------- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index ecbfab5a7..29ca9f989 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -495,4 +495,25 @@ public class CollectorUtil { }; } + + /** + *

    过滤

    + * + * @param predicate 断言 + * @param downstream 下游操作 + * @param 元素类型 + * @param 中间类型 + * @param 结束类型 + * @return 一个用于过滤元素的 {@link java.util.stream.Collector} + * @author TanShengYuan + */ + public static + Collector filtering(final Predicate predicate, + final Collector downstream) { + final BiConsumer downstreamAccumulator = downstream.accumulator(); + return new SimpleCollector<>(downstream.supplier(), + (r, t) -> Opt.of(t).filter(predicate).ifPresent(e -> downstreamAccumulator.accept(r, e)), + downstream.combiner(), downstream.finisher(), + downstream.characteristics()); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java index a56eefd30..9fb5959d9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java @@ -20,50 +20,62 @@ public class CollectorUtilTest { @Test public void reduceListMapTest() { final Set> nameScoreMapList = StreamUtil.of( - // 集合内的第一个map,包含两个key value - MapUtil.builder("苏格拉底", 1).put("特拉叙马霍斯", 3).build(), - MapUtil.of("苏格拉底", 2), - MapUtil.of("特拉叙马霍斯", 1), - MapUtil.of("特拉叙马霍斯", 2) + // 集合内的第一个map,包含两个key value + MapUtil.builder("苏格拉底", 1).put("特拉叙马霍斯", 3).build(), + MapUtil.of("苏格拉底", 2), + MapUtil.of("特拉叙马霍斯", 1), + MapUtil.of("特拉叙马霍斯", 2) ).collect(Collectors.toSet()); // 执行聚合 final Map> nameScoresMap = nameScoreMapList.stream().collect(CollectorUtil.reduceListMap()); Assert.assertEquals(MapUtil.builder("苏格拉底", Arrays.asList(1, 2)) - .put("特拉叙马霍斯", Arrays.asList(3, 1, 2)).build(), - nameScoresMap); + .put("特拉叙马霍斯", Arrays.asList(3, 1, 2)).build(), + nameScoresMap); } @Test public void testTransform() { Stream stream = Stream.of(1, 2, 3, 4) - .collect(CollectorUtil.transform(EasyStream::of)); + .collect(CollectorUtil.transform(EasyStream::of)); Assert.assertEquals(EasyStream.class, stream.getClass()); stream = Stream.of(1, 2, 3, 4) - .collect(CollectorUtil.transform(HashSet::new, EasyStream::of)); + .collect(CollectorUtil.transform(HashSet::new, EasyStream::of)); Assert.assertEquals(EasyStream.class, stream.getClass()); } @Test public void testToEasyStream() { - final Stream stream =Stream.of(1, 2, 3, 4) - .collect(CollectorUtil.toEasyStream()); + final Stream stream = Stream.of(1, 2, 3, 4) + .collect(CollectorUtil.toEasyStream()); Assert.assertEquals(EasyStream.class, stream.getClass()); } @Test public void testToEntryStream() { final Map map = Stream.of(1, 2, 3, 4, 5) - // 转为EntryStream - .collect(CollectorUtil.toEntryStream(Function.identity(), String::valueOf)) - // 过滤偶数 - .filterByKey(k -> (k & 1) == 1) - .inverse() - .toMap(); - Assert.assertEquals((Integer)1, map.get("1")); - Assert.assertEquals((Integer)3, map.get("3")); - Assert.assertEquals((Integer)5, map.get("5")); + // 转为EntryStream + .collect(CollectorUtil.toEntryStream(Function.identity(), String::valueOf)) + // 过滤偶数 + .filterByKey(k -> (k & 1) == 1) + .inverse() + .toMap(); + Assert.assertEquals((Integer) 1, map.get("1")); + Assert.assertEquals((Integer) 3, map.get("3")); + Assert.assertEquals((Integer) 5, map.get("5")); } + @Test + public void testFiltering() { + final Map map = Stream.of(1, 2, 3) + .collect(Collectors.groupingBy(Function.identity(), + CollectorUtil.filtering(i -> i > 1, Collectors.counting()) + )); + Assert.assertEquals(MapUtil.builder() + .put(1, 0L) + .put(2, 1L) + .put(3, 1L) + .build(), map); + } } From 8b9b610ba3920a4d886306ab71583067d875b25b Mon Sep 17 00:00:00 2001 From: Looly Date: Mon, 26 Sep 2022 12:14:15 +0800 Subject: [PATCH 50/73] add security --- .../src/main/java/cn/hutool/crypto/ProviderFactory.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/ProviderFactory.java b/hutool-crypto/src/main/java/cn/hutool/crypto/ProviderFactory.java index 9c52cba09..ff1ab1a0d 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/ProviderFactory.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/ProviderFactory.java @@ -21,6 +21,9 @@ public class ProviderFactory { * @return {@link Provider} */ public static Provider createBouncyCastleProvider() { - return new org.bouncycastle.jce.provider.BouncyCastleProvider(); + final org.bouncycastle.jce.provider.BouncyCastleProvider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); + // issue#2631@Github + SecureUtil.addProvider(provider); + return provider; } } From 7db4d93268047674f41150de4475d5dbc0a0ff5f Mon Sep 17 00:00:00 2001 From: Looly Date: Mon, 26 Sep 2022 18:37:31 +0800 Subject: [PATCH 51/73] add methods --- .../java/cn/hutool/extra/ftp/AbstractFtp.java | 2 +- .../main/java/cn/hutool/extra/ftp/Ftp.java | 92 +++++++++++++------ .../main/java/cn/hutool/extra/ssh/Sftp.java | 19 ++-- .../java/cn/hutool/extra/ssh/SshjSftp.java | 2 +- .../java/cn/hutool/extra/ftp/FtpTest.java | 2 +- .../java/cn/hutool/extra/ssh/SftpTest.java | 2 +- 6 files changed, 81 insertions(+), 38 deletions(-) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java index 245cf0955..fbc08871a 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java @@ -195,7 +195,7 @@ public abstract class AbstractFtp implements Closeable { * @param file 需要上传的文件 * @return 是否成功 */ - public abstract boolean upload(String destPath, File file); + public abstract boolean uploadFile(String destPath, File file); /** * 下载文件 diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java index 7d02f8420..50623cc28 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java @@ -269,10 +269,11 @@ public class Ftp extends AbstractFtp { /** * 是否执行完操作返回当前目录 + * * @return 执行完操作是否返回当前目录 * @since 5.7.17 */ - public boolean isBackToPwd(){ + public boolean isBackToPwd() { return this.backToPwd; } @@ -340,7 +341,7 @@ public class Ftp extends AbstractFtp { * 遍历某个目录下所有文件和目录,不会递归遍历
    * 此方法自动过滤"."和".."两种目录 * - * @param path 目录 + * @param path 目录 * @param predicate 过滤器,null表示不过滤,默认去掉"."和".."两种目录 * @return 文件或目录列表 * @since 5.3.5 @@ -408,6 +409,7 @@ public class Ftp extends AbstractFtp { * * @param path 路径 * @return 状态int,服务端不同,返回不同 + * @throws IORuntimeException IO异常 * @since 5.4.3 */ public int stat(final String path) throws IORuntimeException { @@ -491,39 +493,42 @@ public class Ftp extends AbstractFtp { * 上传文件到指定目录,可选: * *
    -	 * 1. destPath为null或""上传到当前路径
    -	 * 2. destPath为相对路径则相对于当前路径的子路径
    -	 * 3. destPath为绝对路径则上传到此路径
    +	 * 1. remotePath为null或""上传到当前路径
    +	 * 2. remotePath为相对路径则相对于当前路径的子路径
    +	 * 3. remotePath为绝对路径则上传到此路径
     	 * 
    * - * @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径 - * @param file 文件 + * @param remotePath 服务端路径,可以为{@code null} 或者相对路径或绝对路径 + * @param file 文件 * @return 是否上传成功 */ @Override - public boolean upload(final String destPath, final File file) { + public boolean uploadFile(final String remotePath, final File file) { Assert.notNull(file, "file to upload is null !"); - return upload(destPath, file.getName(), file); + if (false == FileUtil.isFile(file)) { + throw new FtpException("[{}] is not a file!", file); + } + return uploadFile(remotePath, file.getName(), file); } /** * 上传文件到指定目录,可选: * *
    -	 * 1. destPath为null或""上传到当前路径
    -	 * 2. destPath为相对路径则相对于当前路径的子路径
    -	 * 3. destPath为绝对路径则上传到此路径
    +	 * 1. remotePath为null或""上传到当前路径
    +	 * 2. remotePath为相对路径则相对于当前路径的子路径
    +	 * 3. remotePath为绝对路径则上传到此路径
     	 * 
    * - * @param file 文件 - * @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径 - * @param fileName 自定义在服务端保存的文件名 + * @param file 文件 + * @param remotePath 服务端路径,可以为{@code null} 或者相对路径或绝对路径 + * @param fileName 自定义在服务端保存的文件名 * @return 是否上传成功 * @throws IORuntimeException IO异常 */ - public boolean upload(final String destPath, final String fileName, final File file) throws IORuntimeException { + public boolean uploadFile(final String remotePath, final String fileName, final File file) throws IORuntimeException { try (final InputStream in = FileUtil.getInputStream(file)) { - return upload(destPath, fileName, in); + return uploadFile(remotePath, fileName, in); } catch (final IOException e) { throw new IORuntimeException(e); } @@ -533,18 +538,18 @@ public class Ftp extends AbstractFtp { * 上传文件到指定目录,可选: * *
    -	 * 1. destPath为null或""上传到当前路径
    -	 * 2. destPath为相对路径则相对于当前路径的子路径
    -	 * 3. destPath为绝对路径则上传到此路径
    +	 * 1. remotePath为null或""上传到当前路径
    +	 * 2. remotePath为相对路径则相对于当前路径的子路径
    +	 * 3. remotePath为绝对路径则上传到此路径
     	 * 
    * - * @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径 + * @param remotePath 服务端路径,可以为{@code null} 或者相对路径或绝对路径 * @param fileName 文件名 * @param fileStream 文件流 * @return 是否上传成功 * @throws IORuntimeException IO异常 */ - public boolean upload(final String destPath, final String fileName, final InputStream fileStream) throws IORuntimeException { + public boolean uploadFile(final String remotePath, final String fileName, final InputStream fileStream) throws IORuntimeException { try { client.setFileType(FTPClient.BINARY_FILE_TYPE); } catch (final IOException e) { @@ -556,10 +561,10 @@ public class Ftp extends AbstractFtp { pwd = pwd(); } - if (StrUtil.isNotBlank(destPath)) { - mkDirs(destPath); - if (false == cd(destPath)) { - throw new FtpException("Change dir to [{}] error, maybe dir not exist!", destPath); + if (StrUtil.isNotBlank(remotePath)) { + mkDirs(remotePath); + if (false == cd(remotePath)) { + throw new FtpException("Change dir to [{}] error, maybe dir not exist!", remotePath); } } @@ -574,6 +579,41 @@ public class Ftp extends AbstractFtp { } } + /** + * 递归上传文件(支持目录)
    + * 上传时,如果uploadFile为目录,只复制目录下所有目录和文件到目标路径下,并不会复制目录本身
    + * 上传时,自动创建父级目录 + * + * @param remotePath 目录路径 + * @param uploadFile 上传文件或目录 + */ + public void upload(final String remotePath, final File uploadFile) { + if (false == FileUtil.isDirectory(uploadFile)) { + this.uploadFile(remotePath, uploadFile); + return; + } + + final File[] files = uploadFile.listFiles(); + if (ArrayUtil.isEmpty(files)) { + return; + } + + final List dirs = new ArrayList<>(files.length); + //第一次只处理文件,防止目录在前面导致先处理子目录,而引发文件所在目录不正确 + for (final File f : files) { + if (f.isDirectory()) { + dirs.add(f); + } else { + this.uploadFile(remotePath, f); + } + } + //第二次只处理目录 + for (final File f : dirs) { + final String dir = FileUtil.normalize(remotePath + "/" + f.getName()); + upload(dir, f); + } + } + /** * 下载文件 * diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java index a1bb581c3..39f74bcba 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java @@ -473,11 +473,11 @@ public class Sftp extends AbstractFtp { /** * 将本地文件或者文件夹同步(覆盖)上传到远程路径 * - * @param file 文件或者文件夹 * @param remotePath 远程路径 + * @param file 文件或者文件夹 * @since 5.7.6 */ - public void syncUpload(final File file, final String remotePath) { + public void upload(final String remotePath, final File file) { if (false == FileUtil.exist(file)) { return; } @@ -489,19 +489,22 @@ public class Sftp extends AbstractFtp { for (final File fileItem : files) { if (fileItem.isDirectory()) { final String mkdir = FileUtil.normalize(remotePath + "/" + fileItem.getName()); - this.syncUpload(fileItem, mkdir); + this.upload(mkdir, fileItem); } else { - this.syncUpload(fileItem, remotePath); + this.uploadFile(remotePath, fileItem); } } } else { - this.mkDirs(remotePath); - this.upload(remotePath, file); + this.uploadFile(remotePath, file); } } @Override - public boolean upload(final String destPath, final File file) { + public boolean uploadFile(final String destPath, final File file) { + if(false == FileUtil.isFile(file)){ + throw new FtpException("[{}] is not a file!", file); + } + this.mkDirs(destPath); put(FileUtil.getAbsolutePath(file), destPath); return true; } @@ -521,7 +524,7 @@ public class Sftp extends AbstractFtp { * @return 是否上传成功 * @since 5.7.16 */ - public boolean upload(String destPath, final String fileName, final InputStream fileStream) { + public boolean uploadFile(String destPath, final String fileName, final InputStream fileStream) { destPath = StrUtil.addSuffixIfNot(destPath, StrUtil.SLASH) + StrUtil.removePrefix(fileName, StrUtil.SLASH); put(fileStream, destPath, null, Mode.OVERWRITE); return true; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/SshjSftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/SshjSftp.java index 982c3290b..36d843b82 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/SshjSftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/SshjSftp.java @@ -183,7 +183,7 @@ public class SshjSftp extends AbstractFtp { } @Override - public boolean upload(final String destPath, final File file) { + public boolean uploadFile(final String destPath, final File file) { try { sftp.put(new FileSystemFile(file), destPath); return containsFile(destPath); diff --git a/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java b/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java index 4e817b4ed..84b78366e 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java @@ -27,7 +27,7 @@ public class FtpTest { public void uploadTest() { final Ftp ftp = new Ftp("localhost"); - final boolean upload = ftp.upload("/temp", FileUtil.file("d:/test/test.zip")); + final boolean upload = ftp.uploadFile("/temp", FileUtil.file("d:/test/test.zip")); Console.log(upload); IoUtil.close(ftp); diff --git a/hutool-extra/src/test/java/cn/hutool/extra/ssh/SftpTest.java b/hutool-extra/src/test/java/cn/hutool/extra/ssh/SftpTest.java index 8ce0f797b..42e6e7d68 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/ssh/SftpTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/ssh/SftpTest.java @@ -42,7 +42,7 @@ public class SftpTest { @Test @Ignore public void uploadTest() { - sshjSftp.upload("/home/test/temp/", new File("C:\\Users\\akwangl\\Downloads\\temp\\辽宁_20190718_104324.CIME")); + sshjSftp.uploadFile("/home/test/temp/", new File("C:\\Users\\akwangl\\Downloads\\temp\\辽宁_20190718_104324.CIME")); } @Test From 42b66729710967b8715b9f3c6d6ceed6029b385c Mon Sep 17 00:00:00 2001 From: duandazhi Date: Tue, 27 Sep 2022 09:37:27 +0800 Subject: [PATCH 52/73] =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=B1=BB=EF=BC=9AsubStr=E5=A2=9E=E5=8A=A0=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B=E3=80=81=E4=BB=A3=E7=A0=81=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hutool/core/text/CharSequenceUtil.java | 9 +++++++++ .../src/test/java/cn/hutool/core/text/StrUtilTest.java | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java index ffd27977f..e217b9f09 100755 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java @@ -1741,6 +1741,15 @@ public class CharSequenceUtil extends StrChecker { /** * 切割指定位置之前部分的字符串 + *

    安全的subString,允许:string为null,允许string长度小于toIndexExclude长度

    + *
    +	 *      Assert.assertEquals(StrUtil.subPre(null, 3), null);
    +	 * 		Assert.assertEquals(StrUtil.subPre("ab", 3), "ab");
    +	 * 		Assert.assertEquals(StrUtil.subPre("abc", 3), "abc");
    +	 * 		Assert.assertEquals(StrUtil.subPre("abcd", 3), "abc");
    +	 * 		Assert.assertEquals(StrUtil.subPre("abcd", -3), "a");
    +	 * 		Assert.assertEquals(StrUtil.subPre("ab", 3), "ab");
    +	 * 
    * * @param string 字符串 * @param toIndexExclude 切割到的位置(不包括) diff --git a/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java index 0e868f6ce..7f380e5b7 100644 --- a/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/StrUtilTest.java @@ -280,6 +280,16 @@ public class StrUtilTest { Assert.assertEquals("ghigh", pre); } + @Test + public void subPreTest() { + Assert.assertEquals(StrUtil.subPre(null, 3), null); + Assert.assertEquals(StrUtil.subPre("ab", 3), "ab"); + Assert.assertEquals(StrUtil.subPre("abc", 3), "abc"); + Assert.assertEquals(StrUtil.subPre("abcd", 3), "abc"); + Assert.assertEquals(StrUtil.subPre("abcd", -3), "a"); + Assert.assertEquals(StrUtil.subPre("ab", 3), "ab"); + } + @Test public void subByCodePointTest() { // 🤔👍🍓🤔 From 246e61678ee5a01f001fb35384c4e48490b86d0a Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 27 Sep 2022 12:19:26 +0800 Subject: [PATCH 53/73] fix doc --- .../src/main/java/cn/hutool/core/text/CharSequenceUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java index e217b9f09..c4964cd87 100755 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java @@ -1742,14 +1742,14 @@ public class CharSequenceUtil extends StrChecker { /** * 切割指定位置之前部分的字符串 *

    安全的subString,允许:string为null,允许string长度小于toIndexExclude长度

    - *
    +	 * 
    {@code
     	 *      Assert.assertEquals(StrUtil.subPre(null, 3), null);
     	 * 		Assert.assertEquals(StrUtil.subPre("ab", 3), "ab");
     	 * 		Assert.assertEquals(StrUtil.subPre("abc", 3), "abc");
     	 * 		Assert.assertEquals(StrUtil.subPre("abcd", 3), "abc");
     	 * 		Assert.assertEquals(StrUtil.subPre("abcd", -3), "a");
     	 * 		Assert.assertEquals(StrUtil.subPre("ab", 3), "ab");
    -	 * 
    + * }
    * * @param string 字符串 * @param toIndexExclude 切割到的位置(不包括) From d458b1451c3fc58e07859017b5bd6a21fadaad16 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 27 Sep 2022 23:38:05 +0800 Subject: [PATCH 54/73] fix code --- .../core/classloader/JarClassLoader.java | 2 +- .../cn/hutool/core/codec/Base16Codec.java | 6 ++ .../cn/hutool/core/codec/PercentCodec.java | 4 +- .../core/compiler/JavaClassFileObject.java | 2 +- .../core/compiler/JavaSourceCompiler.java | 2 +- .../core/compiler/JavaSourceFileObject.java | 2 +- .../main/java/cn/hutool/core/io/FileUtil.java | 2 +- .../core/io/resource/ClassPathResource.java | 2 +- .../hutool/core/io/resource/FileResource.java | 2 +- .../hutool/core/io/resource/ResourceUtil.java | 2 +- .../hutool/core/io/resource/UrlResource.java | 2 +- .../cn/hutool/core/io/watch/WatchMonitor.java | 2 +- .../cn/hutool/core/io/watch/WatchUtil.java | 2 +- .../core/{ => lang}/builder/Builder.java | 4 +- .../{ => lang}/builder/GenericBuilder.java | 3 +- .../core/{ => lang}/builder/package-info.java | 2 +- .../java/cn/hutool/core/map/MapBuilder.java | 2 +- .../cn/hutool/core/map/multi/RowKeyTable.java | 2 +- .../java/cn/hutool/core/net/Ipv4Util.java | 6 +- ...Generater.java => LocalPortGenerator.java} | 4 +- .../net/{ => ssl}/DefaultTrustManager.java | 2 +- .../core/net/{ => ssl}/SSLContextBuilder.java | 4 +- .../core/net/{ => ssl}/SSLProtocols.java | 2 +- .../cn/hutool/core/net/{ => ssl}/SSLUtil.java | 2 +- .../cn/hutool/core/net/ssl/package-info.java | 6 ++ .../core/net/{ => url}/FormUrlencoded.java | 2 +- .../cn/hutool/core/net/{ => url}/RFC3986.java | 2 +- .../hutool/core/net/{ => url}/URLDecoder.java | 2 +- .../hutool/core/net/{ => url}/URLEncoder.java | 2 +- .../cn/hutool/core/net/{ => url}/URLUtil.java | 3 +- .../cn/hutool/core/net/url/UrlBuilder.java | 12 +-- .../java/cn/hutool/core/net/url/UrlPath.java | 2 - .../java/cn/hutool/core/net/url/UrlQuery.java | 5 +- .../cn/hutool/core/reflect/ClassScanner.java | 4 +- .../cn/hutool/core/reflect/ClassUtil.java | 4 +- .../cn/hutool/core/stream/EasyStream.java | 2 +- .../hutool/core/thread/ExecutorBuilder.java | 2 +- .../core/thread/ThreadFactoryBuilder.java | 2 +- .../core/tree/{Tree.java => MapTree.java} | 81 ++++++++++--------- .../java/cn/hutool/core/tree/TreeBuilder.java | 38 ++++----- .../java/cn/hutool/core/tree/TreeUtil.java | 54 ++++++------- .../core/tree/parser/DefaultNodeParser.java | 4 +- .../hutool/core/tree/parser/NodeParser.java | 4 +- .../java/cn/hutool/core/util/ByteUtil.java | 3 + .../cn/hutool/core/util/CreditCodeUtil.java | 3 + .../java/cn/hutool/core/util/PageUtil.java | 4 +- .../java/cn/hutool/core/util/XmlUtil.java | 1 - .../core/builder/GenericBuilderTest.java | 1 + .../java/cn/hutool/core/lang/DictTest.java | 2 +- .../hutool/core/net/FormUrlencodedTest.java | 1 + .../java/cn/hutool/core/net/RFC3986Test.java | 1 + .../cn/hutool/core/net/URLEncoderTest.java | 2 + .../java/cn/hutool/core/net/URLUtilTest.java | 1 + .../cn/hutool/core/net/UrlDecoderTest.java | 1 + .../java/cn/hutool/core/net/UrlQueryTest.java | 1 + .../cn/hutool/core/tree/Issue2279Test.java | 4 +- .../cn/hutool/core/tree/TreeSearchTest.java | 9 +-- .../java/cn/hutool/core/tree/TreeTest.java | 24 +++--- .../cron/pattern/CronPatternBuilder.java | 2 +- .../cn/hutool/db/sql/ConditionBuilder.java | 2 +- .../java/cn/hutool/db/sql/SqlBuilder.java | 2 +- .../main/java/cn/hutool/extra/mail/Mail.java | 2 +- .../extra/servlet/JakartaServletUtil.java | 2 +- .../cn/hutool/extra/servlet/ServletUtil.java | 2 +- .../java/cn/hutool/extra/ssh/JschUtil.java | 4 +- .../main/java/cn/hutool/http/HttpConfig.java | 2 +- .../java/cn/hutool/http/HttpConnection.java | 2 +- .../main/java/cn/hutool/http/HttpRequest.java | 4 +- .../java/cn/hutool/http/HttpResponse.java | 2 +- .../main/java/cn/hutool/http/HttpUtil.java | 4 +- .../http/cookie/GlobalCookieManager.java | 2 +- .../http/server/HttpServerResponse.java | 2 +- .../http/ssl/AndroidSupportSSLFactory.java | 2 +- .../http/ssl/CustomProtocolsSSLFactory.java | 2 +- .../java/cn/hutool/http/HttpRequestTest.java | 2 +- .../java/cn/hutool/http/IssueI5TFPUTest.java | 13 +++ .../src/main/java/cn/hutool/json/JSON.java | 2 +- .../java/cn/hutool/json/package-info.java | 6 +- .../java/cn/hutool/poi/excel/ExcelWriter.java | 2 +- .../java/cn/hutool/setting/GroupedSet.java | 2 +- 80 files changed, 227 insertions(+), 192 deletions(-) rename hutool-core/src/main/java/cn/hutool/core/{ => lang}/builder/Builder.java (86%) rename hutool-core/src/main/java/cn/hutool/core/{ => lang}/builder/GenericBuilder.java (98%) rename hutool-core/src/main/java/cn/hutool/core/{ => lang}/builder/package-info.java (71%) rename hutool-core/src/main/java/cn/hutool/core/net/{LocalPortGenerater.java => LocalPortGenerator.java} (89%) rename hutool-core/src/main/java/cn/hutool/core/net/{ => ssl}/DefaultTrustManager.java (97%) rename hutool-core/src/main/java/cn/hutool/core/net/{ => ssl}/SSLContextBuilder.java (97%) rename hutool-core/src/main/java/cn/hutool/core/net/{ => ssl}/SSLProtocols.java (96%) mode change 100755 => 100644 rename hutool-core/src/main/java/cn/hutool/core/net/{ => ssl}/SSLUtil.java (98%) create mode 100644 hutool-core/src/main/java/cn/hutool/core/net/ssl/package-info.java rename hutool-core/src/main/java/cn/hutool/core/net/{ => url}/FormUrlencoded.java (95%) rename hutool-core/src/main/java/cn/hutool/core/net/{ => url}/RFC3986.java (98%) mode change 100755 => 100644 rename hutool-core/src/main/java/cn/hutool/core/net/{ => url}/URLDecoder.java (99%) rename hutool-core/src/main/java/cn/hutool/core/net/{ => url}/URLEncoder.java (98%) rename hutool-core/src/main/java/cn/hutool/core/net/{ => url}/URLUtil.java (99%) rename hutool-core/src/main/java/cn/hutool/core/tree/{Tree.java => MapTree.java} (79%) create mode 100644 hutool-http/src/test/java/cn/hutool/http/IssueI5TFPUTest.java diff --git a/hutool-core/src/main/java/cn/hutool/core/classloader/JarClassLoader.java b/hutool-core/src/main/java/cn/hutool/core/classloader/JarClassLoader.java index e6a80e82b..dd284195e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/classloader/JarClassLoader.java +++ b/hutool-core/src/main/java/cn/hutool/core/classloader/JarClassLoader.java @@ -2,7 +2,7 @@ package cn.hutool.core.classloader; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.io.FileUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.reflect.MethodUtil; import java.io.File; diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java index 21becd93b..bbc8192ba 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java @@ -13,7 +13,13 @@ import cn.hutool.core.text.StrUtil; */ public class Base16Codec implements Encoder, Decoder { + /** + * 编码解码器:小写 + */ public static final Base16Codec CODEC_LOWER = new Base16Codec(true); + /** + * 编码解码器:大写 + */ public static final Base16Codec CODEC_UPPER = new Base16Codec(false); private final char[] alphabets; diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/PercentCodec.java b/hutool-core/src/main/java/cn/hutool/core/codec/PercentCodec.java index bab6957ec..8363b30c6 100755 --- a/hutool-core/src/main/java/cn/hutool/core/codec/PercentCodec.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/PercentCodec.java @@ -166,7 +166,9 @@ public class PercentCodec implements Encoder, Serializable { * @author looly * @since 6.0.0 */ - public static class Builder implements cn.hutool.core.builder.Builder { + public static class Builder implements cn.hutool.core.lang.builder.Builder { + private static final long serialVersionUID = 1L; + /** * 从已知PercentCodec创建PercentCodec,会复制给定PercentCodec的安全字符 * diff --git a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileObject.java b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileObject.java index 50d233be4..6db6d22f9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileObject.java +++ b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileObject.java @@ -2,7 +2,7 @@ package cn.hutool.core.compiler; import cn.hutool.core.util.CharUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import javax.tools.SimpleJavaFileObject; import java.io.ByteArrayInputStream; diff --git a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceCompiler.java b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceCompiler.java index 180ba6f16..af7faace9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceCompiler.java +++ b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceCompiler.java @@ -8,7 +8,7 @@ import cn.hutool.core.io.resource.FileResource; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.io.resource.StringResource; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceFileObject.java b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceFileObject.java index a7a1e2e35..d4d2ea4a7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceFileObject.java +++ b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceFileObject.java @@ -2,7 +2,7 @@ package cn.hutool.core.compiler; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.CharUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import javax.tools.SimpleJavaFileObject; import java.io.BufferedInputStream; diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java index a5d416375..3dea69cc9 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java @@ -20,7 +20,7 @@ import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.reflect.ClassUtil; import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.compress.ZipUtil; import java.io.BufferedInputStream; diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/ClassPathResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/ClassPathResource.java index 09328b101..deb7c2c99 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/resource/ClassPathResource.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/ClassPathResource.java @@ -3,7 +3,7 @@ package cn.hutool.core.io.resource; import cn.hutool.core.classloader.ClassLoaderUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ObjUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/FileResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/FileResource.java index 1e1eb10f5..4f9f133fe 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/resource/FileResource.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/FileResource.java @@ -3,7 +3,7 @@ package cn.hutool.core.io.resource; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import java.io.File; import java.io.InputStream; diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java index ceb52f1c8..7bd57ae81 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java @@ -7,7 +7,7 @@ import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.classloader.ClassLoaderUtil; import cn.hutool.core.text.StrUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import java.io.BufferedReader; import java.io.File; diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java index 525f59126..d80e37958 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java @@ -2,7 +2,7 @@ package cn.hutool.core.io.resource; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import java.io.File; import java.io.InputStream; diff --git a/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java b/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java index 288d7b6d3..4d9b3e983 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java @@ -4,7 +4,7 @@ import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.watch.watchers.WatcherChain; import cn.hutool.core.text.StrUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.util.CharUtil; import java.io.File; diff --git a/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchUtil.java index f25215f45..bd8ec72bf 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchUtil.java @@ -1,7 +1,7 @@ package cn.hutool.core.io.watch; import cn.hutool.core.io.IORuntimeException; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import java.io.File; import java.io.IOException; diff --git a/hutool-core/src/main/java/cn/hutool/core/builder/Builder.java b/hutool-core/src/main/java/cn/hutool/core/lang/builder/Builder.java similarity index 86% rename from hutool-core/src/main/java/cn/hutool/core/builder/Builder.java rename to hutool-core/src/main/java/cn/hutool/core/lang/builder/Builder.java index 518ac8ddc..9df30a786 100644 --- a/hutool-core/src/main/java/cn/hutool/core/builder/Builder.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/builder/Builder.java @@ -1,4 +1,4 @@ -package cn.hutool.core.builder; +package cn.hutool.core.lang.builder; import java.io.Serializable; @@ -16,4 +16,4 @@ public interface Builder extends Serializable{ * @return 被构建的对象 */ T build(); -} \ No newline at end of file +} diff --git a/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java b/hutool-core/src/main/java/cn/hutool/core/lang/builder/GenericBuilder.java similarity index 98% rename from hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java rename to hutool-core/src/main/java/cn/hutool/core/lang/builder/GenericBuilder.java index 27fb66156..b85e474ef 100644 --- a/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/builder/GenericBuilder.java @@ -1,4 +1,4 @@ -package cn.hutool.core.builder; +package cn.hutool.core.lang.builder; import cn.hutool.core.lang.func.SerConsumer3; @@ -55,6 +55,7 @@ import java.util.function.Supplier; * * @author TomXin VampireAchao * @since 5.7.21 + * @param 构建对象类型 */ public class GenericBuilder implements Builder { private static final long serialVersionUID = 1L; diff --git a/hutool-core/src/main/java/cn/hutool/core/builder/package-info.java b/hutool-core/src/main/java/cn/hutool/core/lang/builder/package-info.java similarity index 71% rename from hutool-core/src/main/java/cn/hutool/core/builder/package-info.java rename to hutool-core/src/main/java/cn/hutool/core/lang/builder/package-info.java index 800a02855..c29315659 100644 --- a/hutool-core/src/main/java/cn/hutool/core/builder/package-info.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/builder/package-info.java @@ -5,4 +5,4 @@ * @author looly * */ -package cn.hutool.core.builder; \ No newline at end of file +package cn.hutool.core.lang.builder; diff --git a/hutool-core/src/main/java/cn/hutool/core/map/MapBuilder.java b/hutool-core/src/main/java/cn/hutool/core/map/MapBuilder.java index b47857bdc..75dc3b04a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/MapBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapBuilder.java @@ -1,7 +1,7 @@ package cn.hutool.core.map; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import java.util.Map; import java.util.function.Supplier; diff --git a/hutool-core/src/main/java/cn/hutool/core/map/multi/RowKeyTable.java b/hutool-core/src/main/java/cn/hutool/core/map/multi/RowKeyTable.java index 18585bcdb..043d440e3 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/multi/RowKeyTable.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/multi/RowKeyTable.java @@ -1,6 +1,6 @@ package cn.hutool.core.map.multi; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.collection.iter.ComputeIter; import cn.hutool.core.collection.iter.IterUtil; import cn.hutool.core.collection.iter.TransIter; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java b/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java index 1daf470f2..468fe0d47 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java @@ -22,6 +22,9 @@ import java.util.regex.Matcher; */ public class Ipv4Util { + /** + * 本地IP:127.0.0.1 + */ public static final String LOCAL_IP = "127.0.0.1"; /** @@ -162,9 +165,6 @@ public class Ipv4Util { if (matcher.matches()) { return matchAddress(matcher); } -// Validator.validateIpv4(strIP, "Invalid IPv4 address!"); -// final long[] ip = Convert.convert(long[].class, StrUtil.split(strIP, CharUtil.DOT)); -// return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3]; throw new IllegalArgumentException("Invalid IPv4 address!"); } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/LocalPortGenerater.java b/hutool-core/src/main/java/cn/hutool/core/net/LocalPortGenerator.java similarity index 89% rename from hutool-core/src/main/java/cn/hutool/core/net/LocalPortGenerater.java rename to hutool-core/src/main/java/cn/hutool/core/net/LocalPortGenerator.java index 684641351..b91498408 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/LocalPortGenerater.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/LocalPortGenerator.java @@ -12,7 +12,7 @@ import java.util.concurrent.atomic.AtomicInteger; * @since 4.0.3 * */ -public class LocalPortGenerater implements Serializable{ +public class LocalPortGenerator implements Serializable{ private static final long serialVersionUID = 1L; /** 备选的本地端口 */ @@ -23,7 +23,7 @@ public class LocalPortGenerater implements Serializable{ * * @param beginPort 起始端口号 */ - public LocalPortGenerater(final int beginPort) { + public LocalPortGenerator(final int beginPort) { alternativePort = new AtomicInteger(beginPort); } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/DefaultTrustManager.java b/hutool-core/src/main/java/cn/hutool/core/net/ssl/DefaultTrustManager.java similarity index 97% rename from hutool-core/src/main/java/cn/hutool/core/net/DefaultTrustManager.java rename to hutool-core/src/main/java/cn/hutool/core/net/ssl/DefaultTrustManager.java index 41152035b..0c686a02c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/DefaultTrustManager.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/ssl/DefaultTrustManager.java @@ -1,4 +1,4 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.ssl; import javax.net.ssl.SSLEngine; import javax.net.ssl.X509ExtendedTrustManager; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/SSLContextBuilder.java b/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLContextBuilder.java similarity index 97% rename from hutool-core/src/main/java/cn/hutool/core/net/SSLContextBuilder.java rename to hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLContextBuilder.java index ea98734ef..fe62c62e5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/SSLContextBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLContextBuilder.java @@ -1,6 +1,6 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.ssl; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.text.StrUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/SSLProtocols.java b/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLProtocols.java old mode 100755 new mode 100644 similarity index 96% rename from hutool-core/src/main/java/cn/hutool/core/net/SSLProtocols.java rename to hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLProtocols.java index 32e938f9f..bd4897ee8 --- a/hutool-core/src/main/java/cn/hutool/core/net/SSLProtocols.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLProtocols.java @@ -1,4 +1,4 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.ssl; /** * SSL或TLS协议 diff --git a/hutool-core/src/main/java/cn/hutool/core/net/SSLUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLUtil.java similarity index 98% rename from hutool-core/src/main/java/cn/hutool/core/net/SSLUtil.java rename to hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLUtil.java index c62a8f9fd..ecd1f2ac5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/SSLUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLUtil.java @@ -1,4 +1,4 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.ssl; import cn.hutool.core.io.IORuntimeException; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/ssl/package-info.java b/hutool-core/src/main/java/cn/hutool/core/net/ssl/package-info.java new file mode 100644 index 000000000..262be1351 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/net/ssl/package-info.java @@ -0,0 +1,6 @@ +/** + * SSL相关封装 + * + * @author looly + */ +package cn.hutool.core.net.ssl; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/FormUrlencoded.java b/hutool-core/src/main/java/cn/hutool/core/net/url/FormUrlencoded.java similarity index 95% rename from hutool-core/src/main/java/cn/hutool/core/net/FormUrlencoded.java rename to hutool-core/src/main/java/cn/hutool/core/net/url/FormUrlencoded.java index 789b326b6..ac0104d2a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/FormUrlencoded.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/FormUrlencoded.java @@ -1,4 +1,4 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.url; import cn.hutool.core.codec.PercentCodec; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/RFC3986.java b/hutool-core/src/main/java/cn/hutool/core/net/url/RFC3986.java old mode 100755 new mode 100644 similarity index 98% rename from hutool-core/src/main/java/cn/hutool/core/net/RFC3986.java rename to hutool-core/src/main/java/cn/hutool/core/net/url/RFC3986.java index f449205aa..de1d0cadb --- a/hutool-core/src/main/java/cn/hutool/core/net/RFC3986.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/RFC3986.java @@ -1,4 +1,4 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.url; import cn.hutool.core.codec.PercentCodec; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java b/hutool-core/src/main/java/cn/hutool/core/net/url/URLDecoder.java similarity index 99% rename from hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java rename to hutool-core/src/main/java/cn/hutool/core/net/url/URLDecoder.java index 1622a83e6..0dd212271 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/URLDecoder.java @@ -1,4 +1,4 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.url; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharsetUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/URLEncoder.java b/hutool-core/src/main/java/cn/hutool/core/net/url/URLEncoder.java similarity index 98% rename from hutool-core/src/main/java/cn/hutool/core/net/URLEncoder.java rename to hutool-core/src/main/java/cn/hutool/core/net/url/URLEncoder.java index 915fd29f1..c36a73516 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/URLEncoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/URLEncoder.java @@ -1,4 +1,4 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.url; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.util.CharUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/URLUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/url/URLUtil.java similarity index 99% rename from hutool-core/src/main/java/cn/hutool/core/net/URLUtil.java rename to hutool-core/src/main/java/cn/hutool/core/net/url/URLUtil.java index 6f127ec87..163dfcf78 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/URLUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/URLUtil.java @@ -1,4 +1,4 @@ -package cn.hutool.core.net; +package cn.hutool.core.net.url; import cn.hutool.core.classloader.ClassLoaderUtil; import cn.hutool.core.exceptions.UtilException; @@ -7,7 +7,6 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.net.url.UrlQuery; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.CharsetUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java index 4679768c4..2e2ab9193 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java @@ -1,11 +1,9 @@ package cn.hutool.core.net.url; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.lang.Assert; -import cn.hutool.core.net.RFC3986; -import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.text.StrUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.util.CharsetUtil; import java.net.MalformedURLException; import java.net.URI; @@ -63,7 +61,7 @@ public final class UrlBuilder implements Builder { * 是否需要编码`%`
    * 区别对待,如果是,则生成URL时需要重新全部编码,否则跳过所有`%` */ - private boolean needEncodePercent; + private final boolean needEncodePercent; /** * 使用URI构建UrlBuilder @@ -119,7 +117,7 @@ public final class UrlBuilder implements Builder { /** * 使用URL字符串构建UrlBuilder,默认使用UTF-8编码 * - * @param url URL字符串 + * @param url URL字符串 * @return UrlBuilder */ public static UrlBuilder of(final String url) { @@ -197,6 +195,8 @@ public final class UrlBuilder implements Builder { */ public UrlBuilder() { this.charset = CharsetUtil.UTF_8; + // 编码非空情况下做解码 + this.needEncodePercent = true; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlPath.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlPath.java index bbed3d84d..9684fc72b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlPath.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlPath.java @@ -3,8 +3,6 @@ package cn.hutool.core.net.url; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.net.RFC3986; -import cn.hutool.core.net.URLDecoder; import cn.hutool.core.util.CharUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ObjUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java index 54a0a0742..e1d181dfe 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java @@ -6,9 +6,6 @@ import cn.hutool.core.collection.iter.IterUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.TableMap; -import cn.hutool.core.net.FormUrlencoded; -import cn.hutool.core.net.RFC3986; -import cn.hutool.core.net.URLDecoder; import cn.hutool.core.text.StrUtil; import java.nio.charset.Charset; @@ -234,7 +231,7 @@ public class UrlQuery { * @return URL查询字符串 */ public String build(final Charset charset) { - return build(charset, true); + return build(charset, null != charset); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/ClassScanner.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassScanner.java index 0538f0412..025d66e7c 100755 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/ClassScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassScanner.java @@ -6,8 +6,8 @@ import cn.hutool.core.collection.iter.EnumerationIter; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.net.URLDecoder; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLDecoder; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharsetUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java index 39e1d8baf..bae54c757 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ClassUtil.java @@ -6,8 +6,8 @@ import cn.hutool.core.convert.BasicType; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.net.URLDecoder; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLDecoder; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 5de51cdbf..4570b25fe 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -268,7 +268,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream extends Consumer, cn.hutool.core.builder.Builder> { + public interface Builder extends Consumer, cn.hutool.core.lang.builder.Builder> { /** * Adds an element to the unwrap being built. diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ExecutorBuilder.java b/hutool-core/src/main/java/cn/hutool/core/thread/ExecutorBuilder.java index cebdd274d..9a16ae68a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ExecutorBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ExecutorBuilder.java @@ -1,6 +1,6 @@ package cn.hutool.core.thread; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.util.ObjUtil; import java.util.concurrent.ArrayBlockingQueue; diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadFactoryBuilder.java b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadFactoryBuilder.java index d7a128436..18460c462 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadFactoryBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadFactoryBuilder.java @@ -1,6 +1,6 @@ package cn.hutool.core.thread; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.text.StrUtil; import java.lang.Thread.UncaughtExceptionHandler; diff --git a/hutool-core/src/main/java/cn/hutool/core/tree/Tree.java b/hutool-core/src/main/java/cn/hutool/core/tree/MapTree.java similarity index 79% rename from hutool-core/src/main/java/cn/hutool/core/tree/Tree.java rename to hutool-core/src/main/java/cn/hutool/core/tree/MapTree.java index 19674a0a7..3689d5eff 100644 --- a/hutool-core/src/main/java/cn/hutool/core/tree/Tree.java +++ b/hutool-core/src/main/java/cn/hutool/core/tree/MapTree.java @@ -25,13 +25,16 @@ import java.util.function.Predicate; * @author liangbaikai * @since 5.2.1 */ -public class Tree extends LinkedHashMap implements Node { +public class MapTree extends LinkedHashMap implements Node { private static final long serialVersionUID = 1L; private final TreeNodeConfig treeNodeConfig; - private Tree parent; + private MapTree parent; - public Tree() { + /** + * 构造 + */ + public MapTree() { this(null); } @@ -40,7 +43,7 @@ public class Tree extends LinkedHashMap implements Node { * * @param treeNodeConfig TreeNode配置 */ - public Tree(final TreeNodeConfig treeNodeConfig) { + public MapTree(final TreeNodeConfig treeNodeConfig) { this.treeNodeConfig = ObjUtil.defaultIfNull( treeNodeConfig, TreeNodeConfig.DEFAULT_CONFIG); } @@ -61,7 +64,7 @@ public class Tree extends LinkedHashMap implements Node { * @return 父节点 * @since 5.2.4 */ - public Tree getParent() { + public MapTree getParent() { return parent; } @@ -73,7 +76,7 @@ public class Tree extends LinkedHashMap implements Node { * @return 节点 * @since 5.2.4 */ - public Tree getNode(final T id) { + public MapTree getNode(final T id) { return TreeUtil.getNode(this, id); } @@ -115,7 +118,7 @@ public class Tree extends LinkedHashMap implements Node { * @return this * @since 5.2.4 */ - public Tree setParent(final Tree parent) { + public MapTree setParent(final MapTree parent) { this.parent = parent; if (null != parent) { this.setParentId(parent.getId()); @@ -130,7 +133,7 @@ public class Tree extends LinkedHashMap implements Node { } @Override - public Tree setId(final T id) { + public MapTree setId(final T id) { this.put(treeNodeConfig.getIdKey(), id); return this; } @@ -142,7 +145,7 @@ public class Tree extends LinkedHashMap implements Node { } @Override - public Tree setParentId(final T parentId) { + public MapTree setParentId(final T parentId) { this.put(treeNodeConfig.getParentIdKey(), parentId); return this; } @@ -153,7 +156,7 @@ public class Tree extends LinkedHashMap implements Node { } @Override - public Tree setName(final CharSequence name) { + public MapTree setName(final CharSequence name) { this.put(treeNodeConfig.getNameKey(), name); return this; } @@ -164,7 +167,7 @@ public class Tree extends LinkedHashMap implements Node { } @Override - public Tree setWeight(final Comparable weight) { + public MapTree setWeight(final Comparable weight) { this.put(treeNodeConfig.getWeightKey(), weight); return this; } @@ -175,8 +178,8 @@ public class Tree extends LinkedHashMap implements Node { * @return 所有子节点 */ @SuppressWarnings("unchecked") - public List> getChildren() { - return (List>) this.get(treeNodeConfig.getChildrenKey()); + public List> getChildren() { + return (List>) this.get(treeNodeConfig.getChildrenKey()); } /** @@ -195,7 +198,7 @@ public class Tree extends LinkedHashMap implements Node { * @param consumer 节点处理器 * @since 5.7.16 */ - public void walk(final Consumer> consumer) { + public void walk(final Consumer> consumer) { walk(consumer, false); } @@ -206,27 +209,27 @@ public class Tree extends LinkedHashMap implements Node { * @param broadFirst 是否广度优先遍历 * @since 6.0.0 */ - public void walk(final Consumer> consumer, final boolean broadFirst) { + public void walk(final Consumer> consumer, final boolean broadFirst) { if (broadFirst) { // 广度优先遍历 // 加入FIFO队列 - final Queue> queue = new LinkedList<>(); + final Queue> queue = new LinkedList<>(); queue.offer(this); while (false == queue.isEmpty()) { - final Tree node = queue.poll(); + final MapTree node = queue.poll(); consumer.accept(node); - final List> children = node.getChildren(); + final List> children = node.getChildren(); if (CollUtil.isNotEmpty(children)) { children.forEach(queue::offer); } } } else { // 深度优先遍历 // 入栈,FILO - final Stack> stack = new Stack<>(); + final Stack> stack = new Stack<>(); stack.add(this); while (false == stack.isEmpty()) { - final Tree node = stack.pop(); + final MapTree node = stack.pop(); consumer.accept(node); - final List> children = node.getChildren(); + final List> children = node.getChildren(); if (CollUtil.isNotEmpty(children)) { children.forEach(stack::push); } @@ -243,7 +246,7 @@ public class Tree extends LinkedHashMap implements Node { * @see #filter(Predicate) * @since 5.7.17 */ - public Tree filterNew(final Predicate> predicate) { + public MapTree filterNew(final Predicate> predicate) { return cloneTree().filter(predicate); } @@ -256,18 +259,18 @@ public class Tree extends LinkedHashMap implements Node { * @see #filterNew(Predicate) * @since 5.7.17 */ - public Tree filter(final Predicate> predicate) { + public MapTree filter(final Predicate> predicate) { if (null == predicate || predicate.test(this)) { // 本节点满足,则包括所有子节点都保留 return this; } - final List> children = getChildren(); + final List> children = getChildren(); if (CollUtil.isNotEmpty(children)) { // 递归过滤子节点 - final List> filteredChildren = new ArrayList<>(children.size()); - Tree filteredChild; - for (final Tree child : children) { + final List> filteredChildren = new ArrayList<>(children.size()); + MapTree filteredChild; + for (final MapTree child : children) { filteredChild = child.filter(predicate); if (null != filteredChild) { filteredChildren.add(filteredChild); @@ -291,7 +294,7 @@ public class Tree extends LinkedHashMap implements Node { * @param children 子节点列表,如果为{@code null}表示移除子节点 * @return this */ - public Tree setChildren(final List> children) { + public MapTree setChildren(final List> children) { if (null == children) { this.remove(treeNodeConfig.getChildrenKey()); } @@ -307,14 +310,14 @@ public class Tree extends LinkedHashMap implements Node { * @since 5.6.7 */ @SafeVarargs - public final Tree addChildren(final Tree... children) { + public final MapTree addChildren(final MapTree... children) { if (ArrayUtil.isNotEmpty(children)) { - List> childrenList = this.getChildren(); + List> childrenList = this.getChildren(); if (null == childrenList) { childrenList = new ArrayList<>(); setChildren(childrenList); } - for (final Tree child : children) { + for (final MapTree child : children) { child.setParent(this); childrenList.add(child); } @@ -347,8 +350,8 @@ public class Tree extends LinkedHashMap implements Node { * @return 新的节点 * @since 5.7.17 */ - public Tree cloneTree() { - final Tree result = ObjUtil.clone(this); + public MapTree cloneTree() { + final MapTree result = ObjUtil.clone(this); result.setChildren(cloneChildren()); return result; } @@ -358,12 +361,12 @@ public class Tree extends LinkedHashMap implements Node { * * @return 新的子节点列表 */ - private List> cloneChildren() { - final List> children = getChildren(); + private List> cloneChildren() { + final List> children = getChildren(); if (null == children) { return null; } - final List> newChildren = new ArrayList<>(children.size()); + final List> newChildren = new ArrayList<>(children.size()); children.forEach((t) -> newChildren.add(t.cloneTree())); return newChildren; } @@ -375,13 +378,13 @@ public class Tree extends LinkedHashMap implements Node { * @param writer Writer * @param intent 缩进量 */ - private static void printTree(final Tree tree, final PrintWriter writer, final int intent) { + private static void printTree(final MapTree tree, final PrintWriter writer, final int intent) { writer.println(StrUtil.format("{}{}[{}]", StrUtil.repeat(CharUtil.SPACE, intent), tree.getName(), tree.getId())); writer.flush(); - final List> children = tree.getChildren(); + final List> children = tree.getChildren(); if (CollUtil.isNotEmpty(children)) { - for (final Tree child : children) { + for (final MapTree child : children) { printTree(child, writer, intent + 2); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/tree/TreeBuilder.java b/hutool-core/src/main/java/cn/hutool/core/tree/TreeBuilder.java index e41a96ebe..7d883e9e9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/tree/TreeBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/tree/TreeBuilder.java @@ -1,6 +1,6 @@ package cn.hutool.core.tree; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.tree.parser.NodeParser; @@ -17,11 +17,11 @@ import java.util.Map; * * @param ID类型 */ -public class TreeBuilder implements Builder> { +public class TreeBuilder implements Builder> { private static final long serialVersionUID = 1L; - private final Tree root; - private final Map> idTreeMap; + private final MapTree root; + private final Map> idTreeMap; private boolean isBuild; /** @@ -54,7 +54,7 @@ public class TreeBuilder implements Builder> { * @param config 配置 */ public TreeBuilder(final E rootId, final TreeNodeConfig config) { - root = new Tree<>(config); + root = new MapTree<>(config); root.setId(rootId); this.idTreeMap = new HashMap<>(); } @@ -127,7 +127,7 @@ public class TreeBuilder implements Builder> { * @param map 节点列表 * @return this */ - public TreeBuilder append(final Map> map) { + public TreeBuilder append(final Map> map) { checkBuilt(); this.idTreeMap.putAll(map); @@ -140,10 +140,10 @@ public class TreeBuilder implements Builder> { * @param trees 节点列表 * @return this */ - public TreeBuilder append(final Iterable> trees) { + public TreeBuilder append(final Iterable> trees) { checkBuilt(); - for (final Tree tree : trees) { + for (final MapTree tree : trees) { this.idTreeMap.put(tree.getId(), tree); } return this; @@ -161,10 +161,10 @@ public class TreeBuilder implements Builder> { checkBuilt(); final TreeNodeConfig config = this.root.getConfig(); - final Map> map = new LinkedHashMap<>(list.size(), 1); - Tree node; + final Map> map = new LinkedHashMap<>(list.size(), 1); + MapTree node; for (final T t : list) { - node = new Tree<>(config); + node = new MapTree<>(config); nodeParser.parse(t, node); map.put(node.getId(), node); } @@ -185,7 +185,7 @@ public class TreeBuilder implements Builder> { } @Override - public Tree build() { + public MapTree build() { checkBuilt(); buildFromMap(); @@ -211,7 +211,7 @@ public class TreeBuilder implements Builder> { * * @return 树列表 */ - public List> buildList() { + public List> buildList() { if (isBuild) { // 已经构建过了 return this.root.getChildren(); @@ -227,9 +227,9 @@ public class TreeBuilder implements Builder> { return; } - final Map> eTreeMap = MapUtil.sortByValue(this.idTreeMap, false); + final Map> eTreeMap = MapUtil.sortByValue(this.idTreeMap, false); E parentId; - for (final Tree node : eTreeMap.values()) { + for (final MapTree node : eTreeMap.values()) { if (null == node) { continue; } @@ -239,7 +239,7 @@ public class TreeBuilder implements Builder> { continue; } - final Tree parentNode = eTreeMap.get(parentId); + final MapTree parentNode = eTreeMap.get(parentId); if (null != parentNode) { parentNode.addChildren(node); } @@ -265,7 +265,7 @@ public class TreeBuilder implements Builder> { * @param currentDepp 当前层级 * @param maxDeep 最大层级 */ - private void cutTree(final Tree tree, final int currentDepp, final int maxDeep) { + private void cutTree(final MapTree tree, final int currentDepp, final int maxDeep) { if (null == tree) { return; } @@ -275,9 +275,9 @@ public class TreeBuilder implements Builder> { return; } - final List> children = tree.getChildren(); + final List> children = tree.getChildren(); if (CollUtil.isNotEmpty(children)) { - for (final Tree child : children) { + for (final MapTree child : children) { cutTree(child, currentDepp + 1, maxDeep); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/tree/TreeUtil.java b/hutool-core/src/main/java/cn/hutool/core/tree/TreeUtil.java index a93c7be15..29a26f37e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/tree/TreeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/tree/TreeUtil.java @@ -21,10 +21,10 @@ public class TreeUtil { * 构建单root节点树 * * @param list 源数据集合 - * @return {@link Tree} + * @return {@link MapTree} * @since 5.7.2 */ - public static Tree buildSingle(final List> list) { + public static MapTree buildSingle(final List> list) { return buildSingle(list, 0); } @@ -34,7 +34,7 @@ public class TreeUtil { * @param list 源数据集合 * @return List */ - public static List> build(final List> list) { + public static List> build(final List> list) { return build(list, 0); } @@ -45,10 +45,10 @@ public class TreeUtil { * @param ID类型 * @param list 源数据集合 * @param parentId 最顶层父id值 一般为 0 之类 - * @return {@link Tree} + * @return {@link MapTree} * @since 5.7.2 */ - public static Tree buildSingle(final List> list, final E parentId) { + public static MapTree buildSingle(final List> list, final E parentId) { return buildSingle(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>()); } @@ -60,7 +60,7 @@ public class TreeUtil { * @param parentId 最顶层父id值 一般为 0 之类 * @return List */ - public static List> build(final List> list, final E parentId) { + public static List> build(final List> list, final E parentId) { return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>()); } @@ -73,10 +73,10 @@ public class TreeUtil { * @param list 源数据集合 * @param parentId 最顶层父id值 一般为 0 之类 * @param nodeParser 转换器 - * @return {@link Tree} + * @return {@link MapTree} * @since 5.7.2 */ - public static Tree buildSingle(final List list, final E parentId, final NodeParser nodeParser) { + public static MapTree buildSingle(final List list, final E parentId, final NodeParser nodeParser) { return buildSingle(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, nodeParser); } @@ -90,7 +90,7 @@ public class TreeUtil { * @param nodeParser 转换器 * @return List */ - public static List> build(final List list, final E parentId, final NodeParser nodeParser) { + public static List> build(final List list, final E parentId, final NodeParser nodeParser) { return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, nodeParser); } @@ -105,7 +105,7 @@ public class TreeUtil { * @param nodeParser 转换器 * @return List */ - public static List> build(final List list, final E rootId, final TreeNodeConfig treeNodeConfig, final NodeParser nodeParser) { + public static List> build(final List list, final E rootId, final TreeNodeConfig treeNodeConfig, final NodeParser nodeParser) { return buildSingle(list, rootId, treeNodeConfig, nodeParser).getChildren(); } @@ -119,10 +119,10 @@ public class TreeUtil { * @param rootId 最顶层父id值 一般为 0 之类 * @param treeNodeConfig 配置 * @param nodeParser 转换器 - * @return {@link Tree} + * @return {@link MapTree} * @since 5.7.2 */ - public static Tree buildSingle(final List list, final E rootId, final TreeNodeConfig treeNodeConfig, final NodeParser nodeParser) { + public static MapTree buildSingle(final List list, final E rootId, final TreeNodeConfig treeNodeConfig, final NodeParser nodeParser) { return TreeBuilder.of(rootId, treeNodeConfig) .append(list, nodeParser).build(); } @@ -136,7 +136,7 @@ public class TreeUtil { * @return List * @since 5.6.7 */ - public static List> build(final Map> map, final E rootId) { + public static List> build(final Map> map, final E rootId) { return buildSingle(map, rootId).getChildren(); } @@ -147,11 +147,11 @@ public class TreeUtil { * @param ID类型 * @param map 源数据Map * @param rootId 根节点id值 一般为 0 之类 - * @return {@link Tree} + * @return {@link MapTree} * @since 5.7.2 */ - public static Tree buildSingle(final Map> map, final E rootId) { - final Tree tree = CollUtil.getFirstNoneNull(map.values()); + public static MapTree buildSingle(final Map> map, final E rootId) { + final MapTree tree = CollUtil.getFirstNoneNull(map.values()); if (null != tree) { final TreeNodeConfig config = tree.getConfig(); return TreeBuilder.of(rootId, config) @@ -172,19 +172,19 @@ public class TreeUtil { * @return 节点 * @since 5.2.4 */ - public static Tree getNode(final Tree node, final T id) { + public static MapTree getNode(final MapTree node, final T id) { if (ObjUtil.equals(id, node.getId())) { return node; } - final List> children = node.getChildren(); + final List> children = node.getChildren(); if (null == children) { return null; } // 查找子节点 - Tree childNode; - for (final Tree child : children) { + MapTree childNode; + for (final MapTree child : children) { childNode = child.getNode(id); if (null != childNode) { return childNode; @@ -208,7 +208,7 @@ public class TreeUtil { * @return 所有父节点名称列表,node为null返回空List * @since 5.2.4 */ - public static List getParentsName(final Tree node, final boolean includeCurrentNode) { + public static List getParentsName(final MapTree node, final boolean includeCurrentNode) { final List result = new ArrayList<>(); if (null == node) { return result; @@ -218,7 +218,7 @@ public class TreeUtil { result.add(node.getName()); } - Tree parent = node.getParent(); + MapTree parent = node.getParent(); while (null != parent) { result.add(parent.getName()); parent = parent.getParent(); @@ -231,11 +231,11 @@ public class TreeUtil { * * @param id 节点ID * @param 节点ID类型 - * @return {@link Tree} + * @return {@link MapTree} * @since 5.7.2 */ - public static Tree createEmptyNode(final E id) { - return new Tree().setId(id); + public static MapTree createEmptyNode(final E id) { + return new MapTree().setId(id); } /** @@ -246,11 +246,11 @@ public class TreeUtil { * @param 节点ID类型 * @return 树所有节点列表 */ - public static List> toList(final Tree root, final boolean broadFirst) { + public static List> toList(final MapTree root, final boolean broadFirst) { if (Objects.isNull(root)) { return null; } - final List> list = new ArrayList<>(); + final List> list = new ArrayList<>(); root.walk(list::add, broadFirst); return list; diff --git a/hutool-core/src/main/java/cn/hutool/core/tree/parser/DefaultNodeParser.java b/hutool-core/src/main/java/cn/hutool/core/tree/parser/DefaultNodeParser.java index 719529f2a..6ef0c65b7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/tree/parser/DefaultNodeParser.java +++ b/hutool-core/src/main/java/cn/hutool/core/tree/parser/DefaultNodeParser.java @@ -1,7 +1,7 @@ package cn.hutool.core.tree.parser; import cn.hutool.core.tree.TreeNode; -import cn.hutool.core.tree.Tree; +import cn.hutool.core.tree.MapTree; import cn.hutool.core.map.MapUtil; import java.util.Map; @@ -15,7 +15,7 @@ import java.util.Map; public class DefaultNodeParser implements NodeParser, T> { @Override - public void parse(final TreeNode treeNode, final Tree tree) { + public void parse(final TreeNode treeNode, final MapTree tree) { tree.setId(treeNode.getId()); tree.setParentId(treeNode.getParentId()); tree.setWeight(treeNode.getWeight()); diff --git a/hutool-core/src/main/java/cn/hutool/core/tree/parser/NodeParser.java b/hutool-core/src/main/java/cn/hutool/core/tree/parser/NodeParser.java index d5b7de335..0dc8a5251 100644 --- a/hutool-core/src/main/java/cn/hutool/core/tree/parser/NodeParser.java +++ b/hutool-core/src/main/java/cn/hutool/core/tree/parser/NodeParser.java @@ -1,6 +1,6 @@ package cn.hutool.core.tree.parser; -import cn.hutool.core.tree.Tree; +import cn.hutool.core.tree.MapTree; /** * 树节点解析器 可以参考{@link DefaultNodeParser} @@ -14,6 +14,6 @@ public interface NodeParser { * @param object 源数据实体 * @param treeNode 树节点实体 */ - void parse(T object, Tree treeNode); + void parse(T object, MapTree treeNode); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ByteUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ByteUtil.java index d5d0ff30d..e57fe87ae 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ByteUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ByteUtil.java @@ -29,6 +29,9 @@ import java.util.concurrent.atomic.LongAdder; */ public class ByteUtil { + /** + * 默认字节序:大端在前,小端在后 + */ public static final ByteOrder DEFAULT_ORDER = ByteOrder.LITTLE_ENDIAN; /** * CPU的字节序 diff --git a/hutool-core/src/main/java/cn/hutool/core/util/CreditCodeUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/CreditCodeUtil.java index 2e0486494..91984f836 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/CreditCodeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/CreditCodeUtil.java @@ -25,6 +25,9 @@ import java.util.regex.Pattern; */ public class CreditCodeUtil { + /** + * 统一社会信用代码正则 + */ public static final Pattern CREDIT_CODE_PATTERN = PatternPool.CREDIT_CODE; /** diff --git a/hutool-core/src/main/java/cn/hutool/core/util/PageUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/PageUtil.java index 7753135cc..3c49f1d5e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/PageUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/PageUtil.java @@ -174,7 +174,7 @@ public class PageUtil { * @param pageSize 每页数 * @return 总页数 */ - public static int totalPage(int totalCount, int pageSize) { + public static int totalPage(final int totalCount, final int pageSize) { return totalPage((long) totalCount, pageSize); } @@ -186,7 +186,7 @@ public class PageUtil { * @return 总页数 * @since 5.8.5 */ - public static int totalPage(long totalCount, int pageSize) { + public static int totalPage(final long totalCount, final int pageSize) { if (pageSize == 0) { return 0; } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/XmlUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/XmlUtil.java index d342bb496..2a97cb106 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/XmlUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/XmlUtil.java @@ -1487,7 +1487,6 @@ public class XmlUtil { */ private void examineNode(final Node node, final boolean attributesOnly) { final NamedNodeMap attributes = node.getAttributes(); - //noinspection ConstantConditions if (null != attributes) { final int length = attributes.getLength(); for (int i = 0; i < length; i++) { diff --git a/hutool-core/src/test/java/cn/hutool/core/builder/GenericBuilderTest.java b/hutool-core/src/test/java/cn/hutool/core/builder/GenericBuilderTest.java index f4240f095..0703f1848 100644 --- a/hutool-core/src/test/java/cn/hutool/core/builder/GenericBuilderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/builder/GenericBuilderTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.builder; +import cn.hutool.core.lang.builder.GenericBuilder; import cn.hutool.core.text.StrUtil; import lombok.Getter; import lombok.Setter; diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/DictTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/DictTest.java index 8bfcbcb43..109675521 100755 --- a/hutool-core/src/test/java/cn/hutool/core/lang/DictTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/DictTest.java @@ -1,6 +1,6 @@ package cn.hutool.core.lang; -import cn.hutool.core.builder.GenericBuilder; +import cn.hutool.core.lang.builder.GenericBuilder; import cn.hutool.core.date.DateTime; import cn.hutool.core.map.Dict; import lombok.AllArgsConstructor; diff --git a/hutool-core/src/test/java/cn/hutool/core/net/FormUrlencodedTest.java b/hutool-core/src/test/java/cn/hutool/core/net/FormUrlencodedTest.java index c44bd0397..51ee92c64 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/FormUrlencodedTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/FormUrlencodedTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.net; +import cn.hutool.core.net.url.FormUrlencoded; import cn.hutool.core.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java b/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java index 786d4d856..740e8cd8f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java @@ -1,5 +1,6 @@ package cn.hutool.core.net; +import cn.hutool.core.net.url.RFC3986; import cn.hutool.core.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-core/src/test/java/cn/hutool/core/net/URLEncoderTest.java b/hutool-core/src/test/java/cn/hutool/core/net/URLEncoderTest.java index 22d40c237..d03988639 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/URLEncoderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/URLEncoderTest.java @@ -1,5 +1,7 @@ package cn.hutool.core.net; +import cn.hutool.core.net.url.URLDecoder; +import cn.hutool.core.net.url.URLEncoder; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-core/src/test/java/cn/hutool/core/net/URLUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/net/URLUtilTest.java index 45b59fc2d..eeb690cba 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/URLUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/URLUtilTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.net; +import cn.hutool.core.net.url.URLUtil; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-core/src/test/java/cn/hutool/core/net/UrlDecoderTest.java b/hutool-core/src/test/java/cn/hutool/core/net/UrlDecoderTest.java index 12cac566b..48fa6eece 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/UrlDecoderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/UrlDecoderTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.net; +import cn.hutool.core.net.url.URLDecoder; import cn.hutool.core.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java b/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java index d47c4a98c..ad2b3fbab 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java @@ -1,6 +1,7 @@ package cn.hutool.core.net; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.net.url.UrlQuery; import cn.hutool.core.util.CharsetUtil; diff --git a/hutool-core/src/test/java/cn/hutool/core/tree/Issue2279Test.java b/hutool-core/src/test/java/cn/hutool/core/tree/Issue2279Test.java index d56cc38d3..768e6c696 100755 --- a/hutool-core/src/test/java/cn/hutool/core/tree/Issue2279Test.java +++ b/hutool-core/src/test/java/cn/hutool/core/tree/Issue2279Test.java @@ -19,7 +19,7 @@ public class Issue2279Test { new TestTree(4, 2, 4, 4) ); - final List> stringTree = TreeUtil.build(list, "0", + final List> stringTree = TreeUtil.build(list, "0", (object, treeNode) -> { treeNode.setId(object.getId()); treeNode.setName(object.getName()); @@ -28,7 +28,7 @@ public class Issue2279Test { } ); - final Tree result = stringTree.get(0); + final MapTree result = stringTree.get(0); Assert.assertEquals(2, result.getChildren().size()); } diff --git a/hutool-core/src/test/java/cn/hutool/core/tree/TreeSearchTest.java b/hutool-core/src/test/java/cn/hutool/core/tree/TreeSearchTest.java index 941f6559f..e23fca534 100755 --- a/hutool-core/src/test/java/cn/hutool/core/tree/TreeSearchTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/tree/TreeSearchTest.java @@ -1,8 +1,5 @@ package cn.hutool.core.tree; -import cn.hutool.core.tree.Tree; -import cn.hutool.core.tree.TreeNode; -import cn.hutool.core.tree.TreeUtil; import org.junit.Assert; import org.junit.Test; @@ -30,10 +27,10 @@ public class TreeSearchTest { @Test public void searchNode() { - final List> treeItems= TreeUtil.build(all_menu, 0L); + final List> treeItems= TreeUtil.build(all_menu, 0L); - final Tree tree=treeItems.get(0); - final Tree searchResult=tree.getNode(3L); + final MapTree tree=treeItems.get(0); + final MapTree searchResult=tree.getNode(3L); Assert.assertEquals("module-B", searchResult.getName()); } diff --git a/hutool-core/src/test/java/cn/hutool/core/tree/TreeTest.java b/hutool-core/src/test/java/cn/hutool/core/tree/TreeTest.java index 489db4fc8..c14971119 100755 --- a/hutool-core/src/test/java/cn/hutool/core/tree/TreeTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/tree/TreeTest.java @@ -31,16 +31,16 @@ public class TreeTest { @Test public void sampleTreeTest() { - final List> treeList = TreeUtil.build(nodeList, "0"); - for (final Tree tree : treeList) { + final List> treeList = TreeUtil.build(nodeList, "0"); + for (final MapTree tree : treeList) { Assert.assertNotNull(tree); Assert.assertEquals("0", tree.getParentId()); // Console.log(tree); } // 测试通过子节点查找父节点 - final Tree rootNode0 = treeList.get(0); - final Tree parent = rootNode0.getChildren().get(0).getParent(); + final MapTree rootNode0 = treeList.get(0); + final MapTree parent = rootNode0.getChildren().get(0).getParent(); Assert.assertEquals(rootNode0, parent); } @@ -55,7 +55,7 @@ public class TreeTest { treeNodeConfig.setDeep(2); //转换器 - final List> treeNodes = TreeUtil.build(nodeList, "0", treeNodeConfig, + final List> treeNodes = TreeUtil.build(nodeList, "0", treeNodeConfig, (treeNode, tree) -> { tree.setId(treeNode.getId()); tree.setParentId(treeNode.getParentId()); @@ -72,7 +72,7 @@ public class TreeTest { @Test public void walkTest(){ final List ids = new ArrayList<>(); - final Tree tree = TreeUtil.buildSingle(nodeList, "0"); + final MapTree tree = TreeUtil.buildSingle(nodeList, "0"); tree.walk((tr)-> ids.add(tr.getId())); Assert .assertEquals(7, ids.size()); @@ -81,7 +81,7 @@ public class TreeTest { @Test public void walkBroadFirstTest(){ final List ids = new ArrayList<>(); - final Tree tree = TreeUtil.buildSingle(nodeList, "0"); + final MapTree tree = TreeUtil.buildSingle(nodeList, "0"); Console.log(tree); tree.walk((tr)-> ids.add(tr.getId()), true); @@ -91,8 +91,8 @@ public class TreeTest { @Test public void cloneTreeTest(){ - final Tree tree = TreeUtil.buildSingle(nodeList, "0"); - final Tree cloneTree = tree.cloneTree(); + final MapTree tree = TreeUtil.buildSingle(nodeList, "0"); + final MapTree cloneTree = tree.cloneTree(); final List ids = new ArrayList<>(); cloneTree.walk((tr)-> ids.add(tr.getId())); @@ -103,7 +103,7 @@ public class TreeTest { @Test public void filterTest(){ // 经过过滤,丢掉"用户添加"节点 - final Tree tree = TreeUtil.buildSingle(nodeList, "0"); + final MapTree tree = TreeUtil.buildSingle(nodeList, "0"); tree.filter((t)->{ final CharSequence name = t.getName(); return null != name && name.toString().contains("店铺"); @@ -116,10 +116,10 @@ public class TreeTest { @Test public void filterNewTest(){ - final Tree tree = TreeUtil.buildSingle(nodeList, "0"); + final MapTree tree = TreeUtil.buildSingle(nodeList, "0"); // 经过过滤,生成新的树 - final Tree newTree = tree.filterNew((t)->{ + final MapTree newTree = tree.filterNew((t)->{ final CharSequence name = t.getName(); return null != name && name.toString().contains("店铺"); }); diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPatternBuilder.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPatternBuilder.java index ac2adb55b..18fcfb338 100644 --- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPatternBuilder.java +++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/CronPatternBuilder.java @@ -1,6 +1,6 @@ package cn.hutool.cron.pattern; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.lang.Assert; import cn.hutool.core.text.StrJoiner; import cn.hutool.core.util.ArrayUtil; diff --git a/hutool-db/src/main/java/cn/hutool/db/sql/ConditionBuilder.java b/hutool-db/src/main/java/cn/hutool/db/sql/ConditionBuilder.java index e18f310a5..19a32e3df 100644 --- a/hutool-db/src/main/java/cn/hutool/db/sql/ConditionBuilder.java +++ b/hutool-db/src/main/java/cn/hutool/db/sql/ConditionBuilder.java @@ -1,6 +1,6 @@ package cn.hutool.db.sql; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; diff --git a/hutool-db/src/main/java/cn/hutool/db/sql/SqlBuilder.java b/hutool-db/src/main/java/cn/hutool/db/sql/SqlBuilder.java index 8bedc1020..696283126 100644 --- a/hutool-db/src/main/java/cn/hutool/db/sql/SqlBuilder.java +++ b/hutool-db/src/main/java/cn/hutool/db/sql/SqlBuilder.java @@ -1,6 +1,6 @@ package cn.hutool.db.sql; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/mail/Mail.java b/hutool-extra/src/main/java/cn/hutool/extra/mail/Mail.java index ec97bbb5d..6c0650676 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/mail/Mail.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/mail/Mail.java @@ -1,6 +1,6 @@ package cn.hutool.extra.mail; -import cn.hutool.core.builder.Builder; +import cn.hutool.core.lang.builder.Builder; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java index ae09fd603..a088c8ea6 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java @@ -11,7 +11,7 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.CaseInsensitiveMap; import cn.hutool.core.map.MapUtil; import cn.hutool.core.net.NetUtil; -import cn.hutool.core.net.URLEncoder; +import cn.hutool.core.net.url.URLEncoder; import cn.hutool.core.net.multipart.MultipartFormData; import cn.hutool.core.net.multipart.UploadSetting; import cn.hutool.core.reflect.ConstructorUtil; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java index 402a94ef5..008934b95 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java @@ -11,7 +11,7 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.CaseInsensitiveMap; import cn.hutool.core.map.MapUtil; import cn.hutool.core.net.NetUtil; -import cn.hutool.core.net.URLEncoder; +import cn.hutool.core.net.url.URLEncoder; import cn.hutool.core.net.multipart.MultipartFormData; import cn.hutool.core.net.multipart.UploadSetting; import cn.hutool.core.reflect.ConstructorUtil; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java index 1421077fc..3cd8631f6 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java @@ -3,7 +3,7 @@ package cn.hutool.extra.ssh; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.net.LocalPortGenerater; +import cn.hutool.core.net.LocalPortGenerator; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.text.StrUtil; import com.jcraft.jsch.*; @@ -31,7 +31,7 @@ public class JschUtil { /** * 本地端口生成器 */ - private static final LocalPortGenerater portGenerater = new LocalPortGenerater(10000); + private static final LocalPortGenerator portGenerater = new LocalPortGenerator(10000); /** * 生成一个本地端口,用于远程端口映射 diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpConfig.java b/hutool-http/src/main/java/cn/hutool/http/HttpConfig.java index 2338e77f9..ee3f2e8fd 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpConfig.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpConfig.java @@ -1,7 +1,7 @@ package cn.hutool.http; import cn.hutool.core.lang.Assert; -import cn.hutool.core.net.SSLUtil; +import cn.hutool.core.net.ssl.SSLUtil; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSocketFactory; diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java index 73da28ea1..1d4cda745 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java @@ -1,7 +1,7 @@ package cn.hutool.http; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.reflect.FieldUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ObjUtil; diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java index 3c634c988..60263d720 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -10,12 +10,12 @@ import cn.hutool.core.io.resource.Resource; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.TableMap; -import cn.hutool.core.net.SSLUtil; +import cn.hutool.core.net.ssl.SSLUtil; import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.net.url.UrlQuery; +import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.text.StrUtil; import cn.hutool.http.body.BytesBody; import cn.hutool.http.body.FormUrlEncodedBody; import cn.hutool.http.body.MultipartBody; diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpResponse.java b/hutool-http/src/main/java/cn/hutool/http/HttpResponse.java index 69e5f78d3..f0af91e5c 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpResponse.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpResponse.java @@ -7,7 +7,7 @@ import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.StreamProgress; import cn.hutool.core.lang.Assert; -import cn.hutool.core.net.URLEncoder; +import cn.hutool.core.net.url.URLEncoder; import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.http.cookie.GlobalCookieManager; diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java index d97d8d761..70e1efeb5 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java @@ -6,8 +6,8 @@ import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.StreamProgress; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.net.RFC3986; -import cn.hutool.core.net.URLEncoder; +import cn.hutool.core.net.url.RFC3986; +import cn.hutool.core.net.url.URLEncoder; import cn.hutool.core.net.url.UrlQuery; import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; diff --git a/hutool-http/src/main/java/cn/hutool/http/cookie/GlobalCookieManager.java b/hutool-http/src/main/java/cn/hutool/http/cookie/GlobalCookieManager.java index 5b406817c..0ce8eefee 100644 --- a/hutool-http/src/main/java/cn/hutool/http/cookie/GlobalCookieManager.java +++ b/hutool-http/src/main/java/cn/hutool/http/cookie/GlobalCookieManager.java @@ -2,7 +2,7 @@ package cn.hutool.http.cookie; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.http.HttpConnection; import java.io.IOException; diff --git a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerResponse.java b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerResponse.java index dd26b3353..04e716927 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerResponse.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerResponse.java @@ -3,7 +3,7 @@ package cn.hutool.http.server; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.net.URLEncoder; +import cn.hutool.core.net.url.URLEncoder; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.http.ContentType; diff --git a/hutool-http/src/main/java/cn/hutool/http/ssl/AndroidSupportSSLFactory.java b/hutool-http/src/main/java/cn/hutool/http/ssl/AndroidSupportSSLFactory.java index bfcf02c4a..165c1536b 100644 --- a/hutool-http/src/main/java/cn/hutool/http/ssl/AndroidSupportSSLFactory.java +++ b/hutool-http/src/main/java/cn/hutool/http/ssl/AndroidSupportSSLFactory.java @@ -1,7 +1,7 @@ package cn.hutool.http.ssl; import cn.hutool.core.io.IORuntimeException; -import cn.hutool.core.net.SSLProtocols; +import cn.hutool.core.net.ssl.SSLProtocols; /** * 兼容android低版本SSL连接
    diff --git a/hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java b/hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java index b5eada654..c7cbc3332 100644 --- a/hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java +++ b/hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java @@ -1,7 +1,7 @@ package cn.hutool.http.ssl; import cn.hutool.core.io.IORuntimeException; -import cn.hutool.core.net.SSLUtil; +import cn.hutool.core.net.ssl.SSLUtil; import cn.hutool.core.util.ArrayUtil; import javax.net.ssl.SSLSocket; diff --git a/hutool-http/src/test/java/cn/hutool/http/HttpRequestTest.java b/hutool-http/src/test/java/cn/hutool/http/HttpRequestTest.java index d34012c7a..5c2919f94 100644 --- a/hutool-http/src/test/java/cn/hutool/http/HttpRequestTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/HttpRequestTest.java @@ -3,7 +3,7 @@ package cn.hutool.http; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.StopWatch; import cn.hutool.core.lang.Console; -import cn.hutool.core.net.SSLProtocols; +import cn.hutool.core.net.ssl.SSLProtocols; import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.util.CharsetUtil; import org.junit.Ignore; diff --git a/hutool-http/src/test/java/cn/hutool/http/IssueI5TFPUTest.java b/hutool-http/src/test/java/cn/hutool/http/IssueI5TFPUTest.java new file mode 100644 index 000000000..ecb75d970 --- /dev/null +++ b/hutool-http/src/test/java/cn/hutool/http/IssueI5TFPUTest.java @@ -0,0 +1,13 @@ +package cn.hutool.http; + +import cn.hutool.core.net.url.UrlBuilder; +import org.junit.Assert; +import org.junit.Test; + +public class IssueI5TFPUTest { + @Test + public void urlBuilderTest() { + final UrlBuilder urlBuilder = UrlBuilder.of("https://hutool.cn", null).addQuery("opt", "%"); + Assert.assertEquals("https://hutool.cn?opt=%", urlBuilder.toString()); + } +} diff --git a/hutool-json/src/main/java/cn/hutool/json/JSON.java b/hutool-json/src/main/java/cn/hutool/json/JSON.java index 134cc98b1..1c3ac9edf 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSON.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSON.java @@ -178,7 +178,7 @@ public interface JSON extends Converter, Cloneable, Serializable { } @Override - default Object convert(Type targetType, Object value) throws ConvertException { + default Object convert(final Type targetType, final Object value) throws ConvertException { return JSONConverter.of(getConfig()).convert(targetType, value); } } diff --git a/hutool-json/src/main/java/cn/hutool/json/package-info.java b/hutool-json/src/main/java/cn/hutool/json/package-info.java index 19284b604..c9ef526da 100644 --- a/hutool-json/src/main/java/cn/hutool/json/package-info.java +++ b/hutool-json/src/main/java/cn/hutool/json/package-info.java @@ -6,9 +6,9 @@ * * JSON封装主要包括JSON表示和JSON转换: * - *
    - *     Java对象   <---->   JSON对象   <----> JSON字符串
    - * 
    + *
    {@code
    + *     Java对象   <---->   JSON对象   <---->    JSON字符串
    + * }
    * * * @author looly diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java index 8d7da672c..d1feddc9d 100755 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java @@ -13,7 +13,7 @@ import cn.hutool.core.map.SafeConcurrentHashMap; import cn.hutool.core.map.TableMap; import cn.hutool.core.map.multi.RowKeyTable; import cn.hutool.core.map.multi.Table; -import cn.hutool.core.net.URLEncoder; +import cn.hutool.core.net.url.URLEncoder; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.poi.excel.cell.CellLocation; diff --git a/hutool-setting/src/main/java/cn/hutool/setting/GroupedSet.java b/hutool-setting/src/main/java/cn/hutool/setting/GroupedSet.java index 5663a8412..ae9f68990 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/GroupedSet.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/GroupedSet.java @@ -3,7 +3,7 @@ package cn.hutool.setting; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.net.URLUtil; +import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharsetUtil; From e4d7d6b7d4f307fdddca971dcedd44abf38cda87 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 27 Sep 2022 23:39:24 +0800 Subject: [PATCH 55/73] update dependency --- hutool-log/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml index e259a6d83..49c78221b 100755 --- a/hutool-log/pom.xml +++ b/hutool-log/pom.xml @@ -18,11 +18,11 @@ - 2.0.0 + 2.0.1 1.3.0 1.2.17 - 2.18.0 + 2.19.0 1.2 1.3.6 From ce11e7147d7d4f782e2e21f9f5c6183e0f7b894b Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 29 Sep 2022 18:20:19 +0800 Subject: [PATCH 56/73] fix code --- .../cn/hutool/core/collection/CollUtil.java | 69 ++++--------------- .../main/java/cn/hutool/core/io/FileUtil.java | 25 +++---- .../main/java/cn/hutool/core/io/IoUtil.java | 11 +-- .../java/cn/hutool/core/io/LineHandler.java | 15 ---- .../cn/hutool/core/io/file/FileReader.java | 6 +- .../hutool/core/io/file/LineReadWatcher.java | 10 +-- .../java/cn/hutool/core/io/file/Tailer.java | 24 ++++--- .../cn/hutool/core/io/watch/WatchAction.java | 24 ------- .../cn/hutool/core/io/watch/WatchServer.java | 5 +- .../hutool/core/tree/parser/NodeParser.java | 1 + .../hutool/core/tree/parser/package-info.java | 4 ++ .../cn/hutool/core/util/CoordinateUtil.java | 4 +- .../java/cn/hutool/core/io/IoUtilTest.java | 3 +- .../cn/hutool/cron/task/RunnableTask.java | 9 ++- .../java/cn/hutool/http/HttpRequestTest.java | 32 +++++++++ .../java/cn/hutool/poi/csv/CsvBaseReader.java | 9 +-- .../java/cn/hutool/poi/csv/CsvReader.java | 3 +- .../java/cn/hutool/poi/csv/CsvRowHandler.java | 18 ----- .../java/cn/hutool/poi/excel/ExcelReader.java | 8 +-- .../cn/hutool/poi/excel/cell/CellHandler.java | 21 ------ .../hutool/poi/excel/sax/ExcelSaxReader.java | 8 ++- .../poi/excel/sax/SheetDataSaxHandler.java | 10 ++- .../cn/hutool/poi/excel/ExcelReadTest.java | 5 +- 23 files changed, 135 insertions(+), 189 deletions(-) delete mode 100644 hutool-core/src/main/java/cn/hutool/core/io/LineHandler.java delete mode 100644 hutool-core/src/main/java/cn/hutool/core/io/watch/WatchAction.java create mode 100755 hutool-core/src/main/java/cn/hutool/core/tree/parser/package-info.java delete mode 100755 hutool-poi/src/main/java/cn/hutool/poi/csv/CsvRowHandler.java delete mode 100644 hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellHandler.java diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java index 44efd239f..2a3a7ec1e 100755 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java @@ -1,6 +1,7 @@ package cn.hutool.core.collection; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.codec.hash.Hash32; import cn.hutool.core.collection.iter.IterUtil; import cn.hutool.core.collection.iter.IteratorEnumeration; import cn.hutool.core.comparator.CompareUtil; @@ -9,7 +10,8 @@ import cn.hutool.core.comparator.PropertyComparator; import cn.hutool.core.convert.CompositeConverter; import cn.hutool.core.convert.Convert; import cn.hutool.core.exceptions.UtilException; -import cn.hutool.core.codec.hash.Hash32; +import cn.hutool.core.lang.func.SerBiConsumer; +import cn.hutool.core.lang.func.SerConsumer3; import cn.hutool.core.map.MapUtil; import cn.hutool.core.reflect.ClassUtil; import cn.hutool.core.reflect.ConstructorUtil; @@ -21,7 +23,6 @@ import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.ObjUtil; -import java.io.Serializable; import java.lang.reflect.Type; import java.util.AbstractCollection; import java.util.ArrayList; @@ -1942,14 +1943,14 @@ public class CollUtil { // ------------------------------------------------------------------------------------------------- forEach /** - * 循环遍历 {@link Iterable},使用{@link IndexedConsumer} 接受遍历的每条数据,并针对每条数据做处理 + * 循环遍历 {@link Iterable},使用{@link SerBiConsumer} 接受遍历的每条数据,并针对每条数据做处理 * * @param 集合元素类型 * @param iterable {@link Iterable} - * @param consumer {@link IndexedConsumer} 遍历的每条数据处理器 + * @param consumer {@link SerBiConsumer} 遍历的每条数据处理器 * @since 5.4.7 */ - public static void forEach(final Iterable iterable, final IndexedConsumer consumer) { + public static void forEach(final Iterable iterable, final SerBiConsumer consumer) { if (iterable == null) { return; } @@ -1957,13 +1958,13 @@ public class CollUtil { } /** - * 循环遍历 {@link Iterator},使用{@link IndexedConsumer} 接受遍历的每条数据,并针对每条数据做处理 + * 循环遍历 {@link Iterator},使用{@link SerBiConsumer} 接受遍历的每条数据,并针对每条数据做处理 * * @param 集合元素类型 * @param iterator {@link Iterator} - * @param consumer {@link IndexedConsumer} 遍历的每条数据处理器 + * @param consumer {@link SerBiConsumer} 遍历的每条数据处理器 */ - public static void forEach(final Iterator iterator, final IndexedConsumer consumer) { + public static void forEach(final Iterator iterator, final SerBiConsumer consumer) { if (iterator == null) { return; } @@ -1975,13 +1976,13 @@ public class CollUtil { } /** - * 循环遍历 {@link Enumeration},使用{@link IndexedConsumer} 接受遍历的每条数据,并针对每条数据做处理 + * 循环遍历 {@link Enumeration},使用{@link SerBiConsumer} 接受遍历的每条数据,并针对每条数据做处理 * * @param 集合元素类型 * @param enumeration {@link Enumeration} - * @param consumer {@link IndexedConsumer} 遍历的每条数据处理器 + * @param consumer {@link SerBiConsumer} 遍历的每条数据处理器 */ - public static void forEach(final Enumeration enumeration, final IndexedConsumer consumer) { + public static void forEach(final Enumeration enumeration, final SerBiConsumer consumer) { if (enumeration == null) { return; } @@ -1993,15 +1994,15 @@ public class CollUtil { } /** - * 循环遍历Map,使用{@link IndexedKVConsumer} 接受遍历的每条数据,并针对每条数据做处理
    + * 循环遍历Map,使用{@link SerConsumer3} 接受遍历的每条数据,并针对每条数据做处理
    * 和JDK8中的map.forEach不同的是,此方法支持index * * @param Key类型 * @param Value类型 * @param map {@link Map} - * @param kvConsumer {@link IndexedKVConsumer} 遍历的每条数据处理器 + * @param kvConsumer {@link SerConsumer3} 遍历的每条数据处理器 */ - public static void forEach(final Map map, final IndexedKVConsumer kvConsumer) { + public static void forEach(final Map map, final SerConsumer3 kvConsumer) { if (map == null) { return; } @@ -2260,46 +2261,6 @@ public class CollUtil { iterable.forEach(x -> Optional.ofNullable(map.get(keyGenerate.apply(x))).ifPresent(y -> biConsumer.accept(x, y))); } - // ---------------------------------------------------------------------------------------------- Interface start - - /** - * 针对一个参数做相应的操作
    - * 此函数接口与JDK8中Consumer不同是多提供了index参数,用于标记遍历对象是第几个。 - * - * @param 处理参数类型 - * @author Looly - */ - @FunctionalInterface - public interface IndexedConsumer extends Serializable { - /** - * 接受并处理一个参数 - * - * @param value 参数值 - * @param index 参数在集合中的索引 - */ - void accept(T value, int index); - } - - /** - * 针对两个参数做相应的操作,例如Map中的KEY和VALUE - * - * @param KEY类型 - * @param VALUE类型 - * @author Looly - */ - @FunctionalInterface - public interface IndexedKVConsumer extends Serializable { - /** - * 接受并处理一对参数 - * - * @param key 键 - * @param value 值 - * @param index 参数在集合中的索引 - */ - void accept(K key, V value, int index); - } - // ---------------------------------------------------------------------------------------------- Interface end - /** * 获取Collection或者iterator的大小,此方法可以处理的对象类型如下: *

    - * emoji-java文档以及别名列表见:https://github.com/vdurmont/emoji-java + * emoji-java文档以及别名列表见:... * * @author looly * @since 4.2.1 @@ -65,9 +65,9 @@ public class EmojiUtil { * 例如: * *