From a92d442c264dba6ebb8ea70082e7613010d289a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Wed, 26 Aug 2020 11:26:44 +0800 Subject: [PATCH 1/9] =?UTF-8?q?feat(5.4.1):=20=E5=A2=9E=E5=8A=A0TreeConver?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加TreeConvert,方便的构建树形数据结构 --- .../core/annotation/LeafCollection.java | 18 +++ .../cn/hutool/core/annotation/LeafDecide.java | 21 +++ .../cn/hutool/core/annotation/RootDecide.java | 20 +++ .../LeafCollectionNotFoundException.java | 18 +++ .../cn/hutool/core/lang/tree/TreeConvert.java | 108 ++++++++++++++++ .../core/lang/tree/TreeConvertTest.java | 122 ++++++++++++++++++ 6 files changed, 307 insertions(+) create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/LeafDecide.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/RootDecide.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/exceptions/LeafCollectionNotFoundException.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java new file mode 100644 index 000000000..a05852149 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java @@ -0,0 +1,18 @@ +package cn.hutool.core.annotation; + +import java.lang.annotation.*; + +/** + * 叶容器-当对象存在树型结构,通过此注解标注属性告知存储位置 + * 一般使用容器存储Set,List等 + * + * @author shadow + * @version 5.4.1 + * @since 5.4.1 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface LeafCollection { + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafDecide.java b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafDecide.java new file mode 100644 index 000000000..27e568c49 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafDecide.java @@ -0,0 +1,21 @@ +package cn.hutool.core.annotation; + +/** + * 子节点判断函数接口 + * + * @author shadow + * @version 5.4.1 + * @since 5.4.1 + */ +@FunctionalInterface +public interface LeafDecide { + + /** + * 是否为子节点 + * + * @param root root target + * @param leaf compare target + * @return 是否从属于 root的子节点 + */ + boolean isLeaf(T root, T leaf); +} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RootDecide.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RootDecide.java new file mode 100644 index 000000000..02c4d5db0 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RootDecide.java @@ -0,0 +1,20 @@ +package cn.hutool.core.annotation; + +/** + * 根判定函数接口 + * + * @author shadow + * @version 5.4.1 + * @since 5.4.1 + */ +@FunctionalInterface +public interface RootDecide { + + /** + * 判断是否为根 + * + * @param root 根节点 + * @return 是否是根节点 + */ + boolean isRoot(T root); +} diff --git a/hutool-core/src/main/java/cn/hutool/core/exceptions/LeafCollectionNotFoundException.java b/hutool-core/src/main/java/cn/hutool/core/exceptions/LeafCollectionNotFoundException.java new file mode 100644 index 000000000..1364dcdf4 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/exceptions/LeafCollectionNotFoundException.java @@ -0,0 +1,18 @@ +package cn.hutool.core.exceptions; + +/** + * 叶子容器未找到异常 + * + * @author shadow + * @version 5.4.1 + * @since 5.4.1 + */ +public class LeafCollectionNotFoundException extends RuntimeException { + + /** + * @param message message + */ + public LeafCollectionNotFoundException(String message) { + super(message); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java new file mode 100644 index 000000000..d50dfb21c --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java @@ -0,0 +1,108 @@ +package cn.hutool.core.lang.tree; + +import cn.hutool.core.annotation.LeafCollection; +import cn.hutool.core.annotation.LeafDecide; +import cn.hutool.core.annotation.RootDecide; +import cn.hutool.core.exceptions.LeafCollectionNotFoundException; +import cn.hutool.core.util.ReflectUtil; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.*; + +/** + * 树结构转换工具 + *

+ * 由{@link LeafCollection}注解标注实体,用于存放子节点的容器 + * 函数式两个接口{@link RootDecide} {@link LeafDecide} 判断父子节点定义 + *

+ * 这样可以尽量不更改接口返回的泛型结构 + * + * @author shadow (https://github.com/SHADOW-LI0327) + * @version 5.4.1 + * @since 5.4.1 + */ +public class TreeConvert { + + /** + * 生成树结构 + * 通过反射检测LeafCollection注解,转换为父子结构容器,子数据装入LeafCollection容器中 + * 2020-05-20 修复泛型问题,方便调用 + * + * @param elements 元素组 + * @param clazz 反射类型 !警告! 不可传入包装类型,后续判断失效将抛出异常 + * @param rootDecide 根元素判断函数 + * @param leafDecide 叶子元素判断函数 + * @param 泛型 + * @return List + */ + public static List convert(Collection elements, Class clazz, RootDecide rootDecide, LeafDecide leafDecide) { + List treeList = new ArrayList<>(); + //叶子容器 + Field leafCollection = null; + if (!elements.isEmpty()) { + Field[] fields = ReflectUtil.getFields(clazz); + //一般扩展属性会写在成员变量的后面,倒着找比较快 + for (int i = fields.length - 1; i > 0; i--) { + if (fields[i].getAnnotation(LeafCollection.class) != null) { + //找到既退出迭代查找 + leafCollection = fields[i]; + break; + } + } + //缺少注解抛出异常 + if (leafCollection == null) { + throw new LeafCollectionNotFoundException("注解LeafCollection未找到,请确认子容器"); + } + } + //迭代容器 + for (T element : elements) { + if (rootDecide.isRoot(element)) { + //设立根目录 + treeList.add(element); + //递归 + try { + sort(element, elements, leafDecide, clazz, leafCollection); + } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + return treeList; + } + + + /** + * 递归排序 + * + * @param root 根元素 + * @param elements 元素组 + * @param leafDecide 叶子判断函数 + * @param leafField 叶子容器 + * @param clazz 类型 + * @param 泛型 + * @return List + * @throws IntrospectionException e + * @throws InvocationTargetException e + * @throws IllegalAccessException e + */ + private static List sort(T root, Collection elements, LeafDecide leafDecide, Class clazz, Field leafField) throws IntrospectionException, InvocationTargetException, IllegalAccessException { + List subMenu = null; + for (T element : elements) { + if (leafDecide.isLeaf(root, element)) { + if (subMenu == null) { + subMenu = new ArrayList<>(); + } + List leaf = sort(element, elements, leafDecide, clazz, leafField); + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(leafField.getName(), clazz); + propertyDescriptor.getWriteMethod().invoke(element, leaf); + subMenu.add(element); + } + } + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(leafField.getName(), clazz); + propertyDescriptor.getWriteMethod().invoke(root, subMenu); + return subMenu; + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java new file mode 100644 index 000000000..8dce50835 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java @@ -0,0 +1,122 @@ +package cn.hutool.core.lang.tree; + +import cn.hutool.core.annotation.LeafCollection; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +/** + * 树转换测试 + */ +public class TreeConvertTest { + + // 子父级测试数据 + private List parentChildMaterials = Arrays.asList( + new Dept("00000001", "0", "xxx公司"), + new Dept("00000002", "00000001", "市场部"), + new Dept("00000003", "00000001", "行政部"), + new Dept("00000004", "00000001", "IT部"), + new Dept("00000005", "00000002", "华南"), + new Dept("00000006", "00000002", "华北"), + new Dept("00000007", "00000002", "华东") + ); + + // 排序号测试数据 + private List sortNoMaterials = Arrays.asList( + new Dept("00", "xxx公司"), + new Dept("0010", "市场部"), + new Dept("0020", "行政部"), + new Dept("0030", "IT部"), + new Dept("001010", "华南"), + new Dept("001020", "华北"), + new Dept("001030", "华东") + ); + + // 父子结构测试 + @Test + public void testParentChild() { + List tree = TreeConvert.convert(parentChildMaterials, Dept.class, + root -> "0".equals(root.getParentId()), + (root, leaf) -> leaf.getParentId().equals(root.getDeptId()) + ); + Assert.assertEquals("0", tree.get(0).getParentId()); + } + + // 排序号测试 + @Test + public void testSortNo() { + List tree = TreeConvert.convert(sortNoMaterials, Dept.class, + root -> "00".equals(root.getSortNo()), + (root, leaf) -> + leaf.getSortNo().startsWith(root.getSortNo()) && + !leaf.getSortNo().equals(root.getSortNo()) && + leaf.getSortNo().length() - root.getSortNo().length() == 2 + ); + Assert.assertEquals("0", tree.get(0).getParentId()); + } + + // 测试实体类 + class Dept { + private String deptId; + private String sortNo; + private String parentId; + private String deptName; + @LeafCollection + private List child; + public Dept() { + } + + public Dept(String sortNo, String deptName) { + this.deptName = deptName; + this.sortNo = sortNo; + } + + public Dept(String deptId, String parentId, String deptName) { + this.deptId = deptId; + this.parentId = parentId; + this.deptName = deptName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public List getChild() { + return child; + } + + public void setChild(List child) { + this.child = child; + } + + public String getSortNo() { + return sortNo; + } + + public void setSortNo(String sortNo) { + this.sortNo = sortNo; + } + } +} From 145b8cc6caaf63ea0fb7686a10e116cb10ba213c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Wed, 26 Aug 2020 12:26:49 +0800 Subject: [PATCH 2/9] =?UTF-8?q?feat(5.4.1):=20=E5=A2=9E=E5=8A=A0TreeConver?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加TreeConvert,方便的构建树形数据结构 --- .../core/lang/tree/TreeConvertTest.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java index 8dce50835..602598ca8 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java @@ -11,7 +11,8 @@ import java.util.List; * 树转换测试 */ public class TreeConvertTest { - + // + private static final String ROOT = "0"; // 子父级测试数据 private List parentChildMaterials = Arrays.asList( new Dept("00000001", "0", "xxx公司"), @@ -38,12 +39,22 @@ public class TreeConvertTest { @Test public void testParentChild() { List tree = TreeConvert.convert(parentChildMaterials, Dept.class, - root -> "0".equals(root.getParentId()), + // TreeConvertTest::rootDecide + root -> ROOT.equals(root.getParentId()), + // TreeConvertTest::leafDecide (root, leaf) -> leaf.getParentId().equals(root.getDeptId()) ); - Assert.assertEquals("0", tree.get(0).getParentId()); + Assert.assertEquals(ROOT, tree.get(0).getParentId()); } + // 静态抽象 + public static boolean rootDecide(Dept root) { + return ROOT.equals(root.getDeptId()); + } + // 静态抽象 + public static boolean leafDecide(Dept root, Dept leaf) { + return leaf.getParentId().equals(root.getDeptId()); + } // 排序号测试 @Test public void testSortNo() { @@ -54,7 +65,7 @@ public class TreeConvertTest { !leaf.getSortNo().equals(root.getSortNo()) && leaf.getSortNo().length() - root.getSortNo().length() == 2 ); - Assert.assertEquals("0", tree.get(0).getParentId()); + Assert.assertEquals("00", tree.get(0).getSortNo()); } // 测试实体类 From e27eb9299bd740c05e95cc5313822ab1293188cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Wed, 26 Aug 2020 15:10:26 +0800 Subject: [PATCH 3/9] =?UTF-8?q?fix(5.4.1):=20=E4=BF=AE=E6=94=B9code=20smel?= =?UTF-8?q?l?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.静态工具类构造器私有 2.优化过长方法名 --- .../hutool/core/annotation/LeafCollection.java | 6 +++++- .../cn/hutool/core/lang/tree/TreeConvert.java | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java index a05852149..3d3bfe146 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java @@ -1,6 +1,10 @@ package cn.hutool.core.annotation; -import java.lang.annotation.*; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.lang.annotation.RetentionPolicy; /** * 叶容器-当对象存在树型结构,通过此注解标注属性告知存储位置 diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java index d50dfb21c..d45f4661b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java @@ -10,7 +10,9 @@ import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.util.*; +import java.util.List; +import java.util.Collection; +import java.util.ArrayList; /** * 树结构转换工具 @@ -26,6 +28,13 @@ import java.util.*; */ public class TreeConvert { + /** + * 构造私有化,静态方法不需要暴露公共构造器 + * 修复 Add a private constructor to hide the implicit public one + */ + private TreeConvert() { + + } /** * 生成树结构 * 通过反射检测LeafCollection注解,转换为父子结构容器,子数据装入LeafCollection容器中 @@ -87,8 +96,11 @@ public class TreeConvert { * @throws IntrospectionException e * @throws InvocationTargetException e * @throws IllegalAccessException e + * + * 2020-08-26 修复方法名过长 */ - private static List sort(T root, Collection elements, LeafDecide leafDecide, Class clazz, Field leafField) throws IntrospectionException, InvocationTargetException, IllegalAccessException { + private static List sort(T root, Collection elements, LeafDecide leafDecide, Class clazz, Field leafField) + throws IntrospectionException, InvocationTargetException, IllegalAccessException { List subMenu = null; for (T element : elements) { if (leafDecide.isLeaf(root, element)) { From c560991b73e280aa872addb2b4d1318fce01ebec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Thu, 27 Aug 2020 17:22:38 +0800 Subject: [PATCH 4/9] =?UTF-8?q?Revert=20"fix(5.4.1):=20=E4=BF=AE=E6=94=B9c?= =?UTF-8?q?ode=20smell"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e27eb929 --- .../hutool/core/annotation/LeafCollection.java | 6 +----- .../cn/hutool/core/lang/tree/TreeConvert.java | 16 ++-------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java index 3d3bfe146..a05852149 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java @@ -1,10 +1,6 @@ package cn.hutool.core.annotation; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.*; /** * 叶容器-当对象存在树型结构,通过此注解标注属性告知存储位置 diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java index d45f4661b..d50dfb21c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java @@ -10,9 +10,7 @@ import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.Collection; -import java.util.ArrayList; +import java.util.*; /** * 树结构转换工具 @@ -28,13 +26,6 @@ import java.util.ArrayList; */ public class TreeConvert { - /** - * 构造私有化,静态方法不需要暴露公共构造器 - * 修复 Add a private constructor to hide the implicit public one - */ - private TreeConvert() { - - } /** * 生成树结构 * 通过反射检测LeafCollection注解,转换为父子结构容器,子数据装入LeafCollection容器中 @@ -96,11 +87,8 @@ public class TreeConvert { * @throws IntrospectionException e * @throws InvocationTargetException e * @throws IllegalAccessException e - * - * 2020-08-26 修复方法名过长 */ - private static List sort(T root, Collection elements, LeafDecide leafDecide, Class clazz, Field leafField) - throws IntrospectionException, InvocationTargetException, IllegalAccessException { + private static List sort(T root, Collection elements, LeafDecide leafDecide, Class clazz, Field leafField) throws IntrospectionException, InvocationTargetException, IllegalAccessException { List subMenu = null; for (T element : elements) { if (leafDecide.isLeaf(root, element)) { From f99791b8102279234d80f75f22304a99fcc83181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Thu, 27 Aug 2020 17:22:47 +0800 Subject: [PATCH 5/9] =?UTF-8?q?Revert=20"feat(5.4.1):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?TreeConvert"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 145b8cc6 --- .../core/lang/tree/TreeConvertTest.java | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java index 602598ca8..8dce50835 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java @@ -11,8 +11,7 @@ import java.util.List; * 树转换测试 */ public class TreeConvertTest { - // - private static final String ROOT = "0"; + // 子父级测试数据 private List parentChildMaterials = Arrays.asList( new Dept("00000001", "0", "xxx公司"), @@ -39,22 +38,12 @@ public class TreeConvertTest { @Test public void testParentChild() { List tree = TreeConvert.convert(parentChildMaterials, Dept.class, - // TreeConvertTest::rootDecide - root -> ROOT.equals(root.getParentId()), - // TreeConvertTest::leafDecide + root -> "0".equals(root.getParentId()), (root, leaf) -> leaf.getParentId().equals(root.getDeptId()) ); - Assert.assertEquals(ROOT, tree.get(0).getParentId()); + Assert.assertEquals("0", tree.get(0).getParentId()); } - // 静态抽象 - public static boolean rootDecide(Dept root) { - return ROOT.equals(root.getDeptId()); - } - // 静态抽象 - public static boolean leafDecide(Dept root, Dept leaf) { - return leaf.getParentId().equals(root.getDeptId()); - } // 排序号测试 @Test public void testSortNo() { @@ -65,7 +54,7 @@ public class TreeConvertTest { !leaf.getSortNo().equals(root.getSortNo()) && leaf.getSortNo().length() - root.getSortNo().length() == 2 ); - Assert.assertEquals("00", tree.get(0).getSortNo()); + Assert.assertEquals("0", tree.get(0).getParentId()); } // 测试实体类 From e299cdcea445150515c3331a821ce411f47dd65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Thu, 27 Aug 2020 17:22:54 +0800 Subject: [PATCH 6/9] =?UTF-8?q?Revert=20"feat(5.4.1):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?TreeConvert"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a92d442c --- .../core/annotation/LeafCollection.java | 18 --- .../cn/hutool/core/annotation/LeafDecide.java | 21 --- .../cn/hutool/core/annotation/RootDecide.java | 20 --- .../LeafCollectionNotFoundException.java | 18 --- .../cn/hutool/core/lang/tree/TreeConvert.java | 108 ---------------- .../core/lang/tree/TreeConvertTest.java | 122 ------------------ 6 files changed, 307 deletions(-) delete mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java delete mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/LeafDecide.java delete mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/RootDecide.java delete mode 100644 hutool-core/src/main/java/cn/hutool/core/exceptions/LeafCollectionNotFoundException.java delete mode 100644 hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java delete mode 100644 hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java deleted file mode 100644 index a05852149..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafCollection.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.hutool.core.annotation; - -import java.lang.annotation.*; - -/** - * 叶容器-当对象存在树型结构,通过此注解标注属性告知存储位置 - * 一般使用容器存储Set,List等 - * - * @author shadow - * @version 5.4.1 - * @since 5.4.1 - */ -@Target({ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface LeafCollection { - -} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafDecide.java b/hutool-core/src/main/java/cn/hutool/core/annotation/LeafDecide.java deleted file mode 100644 index 27e568c49..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/LeafDecide.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.hutool.core.annotation; - -/** - * 子节点判断函数接口 - * - * @author shadow - * @version 5.4.1 - * @since 5.4.1 - */ -@FunctionalInterface -public interface LeafDecide { - - /** - * 是否为子节点 - * - * @param root root target - * @param leaf compare target - * @return 是否从属于 root的子节点 - */ - boolean isLeaf(T root, T leaf); -} diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RootDecide.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RootDecide.java deleted file mode 100644 index 02c4d5db0..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/RootDecide.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.hutool.core.annotation; - -/** - * 根判定函数接口 - * - * @author shadow - * @version 5.4.1 - * @since 5.4.1 - */ -@FunctionalInterface -public interface RootDecide { - - /** - * 判断是否为根 - * - * @param root 根节点 - * @return 是否是根节点 - */ - boolean isRoot(T root); -} diff --git a/hutool-core/src/main/java/cn/hutool/core/exceptions/LeafCollectionNotFoundException.java b/hutool-core/src/main/java/cn/hutool/core/exceptions/LeafCollectionNotFoundException.java deleted file mode 100644 index 1364dcdf4..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/exceptions/LeafCollectionNotFoundException.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.hutool.core.exceptions; - -/** - * 叶子容器未找到异常 - * - * @author shadow - * @version 5.4.1 - * @since 5.4.1 - */ -public class LeafCollectionNotFoundException extends RuntimeException { - - /** - * @param message message - */ - public LeafCollectionNotFoundException(String message) { - super(message); - } -} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java deleted file mode 100644 index d50dfb21c..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeConvert.java +++ /dev/null @@ -1,108 +0,0 @@ -package cn.hutool.core.lang.tree; - -import cn.hutool.core.annotation.LeafCollection; -import cn.hutool.core.annotation.LeafDecide; -import cn.hutool.core.annotation.RootDecide; -import cn.hutool.core.exceptions.LeafCollectionNotFoundException; -import cn.hutool.core.util.ReflectUtil; - -import java.beans.IntrospectionException; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.util.*; - -/** - * 树结构转换工具 - *

- * 由{@link LeafCollection}注解标注实体,用于存放子节点的容器 - * 函数式两个接口{@link RootDecide} {@link LeafDecide} 判断父子节点定义 - *

- * 这样可以尽量不更改接口返回的泛型结构 - * - * @author shadow (https://github.com/SHADOW-LI0327) - * @version 5.4.1 - * @since 5.4.1 - */ -public class TreeConvert { - - /** - * 生成树结构 - * 通过反射检测LeafCollection注解,转换为父子结构容器,子数据装入LeafCollection容器中 - * 2020-05-20 修复泛型问题,方便调用 - * - * @param elements 元素组 - * @param clazz 反射类型 !警告! 不可传入包装类型,后续判断失效将抛出异常 - * @param rootDecide 根元素判断函数 - * @param leafDecide 叶子元素判断函数 - * @param 泛型 - * @return List - */ - public static List convert(Collection elements, Class clazz, RootDecide rootDecide, LeafDecide leafDecide) { - List treeList = new ArrayList<>(); - //叶子容器 - Field leafCollection = null; - if (!elements.isEmpty()) { - Field[] fields = ReflectUtil.getFields(clazz); - //一般扩展属性会写在成员变量的后面,倒着找比较快 - for (int i = fields.length - 1; i > 0; i--) { - if (fields[i].getAnnotation(LeafCollection.class) != null) { - //找到既退出迭代查找 - leafCollection = fields[i]; - break; - } - } - //缺少注解抛出异常 - if (leafCollection == null) { - throw new LeafCollectionNotFoundException("注解LeafCollection未找到,请确认子容器"); - } - } - //迭代容器 - for (T element : elements) { - if (rootDecide.isRoot(element)) { - //设立根目录 - treeList.add(element); - //递归 - try { - sort(element, elements, leafDecide, clazz, leafCollection); - } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) { - e.printStackTrace(); - } - } - } - return treeList; - } - - - /** - * 递归排序 - * - * @param root 根元素 - * @param elements 元素组 - * @param leafDecide 叶子判断函数 - * @param leafField 叶子容器 - * @param clazz 类型 - * @param 泛型 - * @return List - * @throws IntrospectionException e - * @throws InvocationTargetException e - * @throws IllegalAccessException e - */ - private static List sort(T root, Collection elements, LeafDecide leafDecide, Class clazz, Field leafField) throws IntrospectionException, InvocationTargetException, IllegalAccessException { - List subMenu = null; - for (T element : elements) { - if (leafDecide.isLeaf(root, element)) { - if (subMenu == null) { - subMenu = new ArrayList<>(); - } - List leaf = sort(element, elements, leafDecide, clazz, leafField); - PropertyDescriptor propertyDescriptor = new PropertyDescriptor(leafField.getName(), clazz); - propertyDescriptor.getWriteMethod().invoke(element, leaf); - subMenu.add(element); - } - } - PropertyDescriptor propertyDescriptor = new PropertyDescriptor(leafField.getName(), clazz); - propertyDescriptor.getWriteMethod().invoke(root, subMenu); - return subMenu; - } -} diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java deleted file mode 100644 index 8dce50835..000000000 --- a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeConvertTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package cn.hutool.core.lang.tree; - -import cn.hutool.core.annotation.LeafCollection; -import org.junit.Assert; -import org.junit.Test; - -import java.util.Arrays; -import java.util.List; - -/** - * 树转换测试 - */ -public class TreeConvertTest { - - // 子父级测试数据 - private List parentChildMaterials = Arrays.asList( - new Dept("00000001", "0", "xxx公司"), - new Dept("00000002", "00000001", "市场部"), - new Dept("00000003", "00000001", "行政部"), - new Dept("00000004", "00000001", "IT部"), - new Dept("00000005", "00000002", "华南"), - new Dept("00000006", "00000002", "华北"), - new Dept("00000007", "00000002", "华东") - ); - - // 排序号测试数据 - private List sortNoMaterials = Arrays.asList( - new Dept("00", "xxx公司"), - new Dept("0010", "市场部"), - new Dept("0020", "行政部"), - new Dept("0030", "IT部"), - new Dept("001010", "华南"), - new Dept("001020", "华北"), - new Dept("001030", "华东") - ); - - // 父子结构测试 - @Test - public void testParentChild() { - List tree = TreeConvert.convert(parentChildMaterials, Dept.class, - root -> "0".equals(root.getParentId()), - (root, leaf) -> leaf.getParentId().equals(root.getDeptId()) - ); - Assert.assertEquals("0", tree.get(0).getParentId()); - } - - // 排序号测试 - @Test - public void testSortNo() { - List tree = TreeConvert.convert(sortNoMaterials, Dept.class, - root -> "00".equals(root.getSortNo()), - (root, leaf) -> - leaf.getSortNo().startsWith(root.getSortNo()) && - !leaf.getSortNo().equals(root.getSortNo()) && - leaf.getSortNo().length() - root.getSortNo().length() == 2 - ); - Assert.assertEquals("0", tree.get(0).getParentId()); - } - - // 测试实体类 - class Dept { - private String deptId; - private String sortNo; - private String parentId; - private String deptName; - @LeafCollection - private List child; - public Dept() { - } - - public Dept(String sortNo, String deptName) { - this.deptName = deptName; - this.sortNo = sortNo; - } - - public Dept(String deptId, String parentId, String deptName) { - this.deptId = deptId; - this.parentId = parentId; - this.deptName = deptName; - } - - public String getDeptId() { - return deptId; - } - - public void setDeptId(String deptId) { - this.deptId = deptId; - } - - public String getParentId() { - return parentId; - } - - public void setParentId(String parentId) { - this.parentId = parentId; - } - - public String getDeptName() { - return deptName; - } - - public void setDeptName(String deptName) { - this.deptName = deptName; - } - - public List getChild() { - return child; - } - - public void setChild(List child) { - this.child = child; - } - - public String getSortNo() { - return sortNo; - } - - public void setSortNo(String sortNo) { - this.sortNo = sortNo; - } - } -} From e58ac72bbbc14cfbd3d21dbcc3f1f55b3013bbb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Fri, 4 Sep 2020 11:56:03 +0800 Subject: [PATCH 7/9] =?UTF-8?q?feat(SpringUtil):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=96=B0=E7=89=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.添加向Spring动态注册Bean的方法 --- .../cn/hutool/extra/spring/SpringUtil.java | 17 ++++++++++ .../hutool/extra/spring/SpringUtilTest.java | 32 ++++++++++++++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringUtil.java index af0be5e8c..59cd3e3cd 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/spring/SpringUtil.java @@ -4,6 +4,7 @@ import cn.hutool.core.lang.TypeReference; import cn.hutool.core.util.ArrayUtil; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.ResolvableType; import org.springframework.stereotype.Component; @@ -148,6 +149,22 @@ public class SpringUtil implements ApplicationContextAware { final String[] activeProfiles = getActiveProfiles(); return ArrayUtil.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; } + + /** + * 动态向Spring注册Bean + *

+ * 由{@link org.springframework.beans.factory.BeanFactory} 实现,通过工具开放API + * + * @param beanName 名称 + * @param bean bean + * @param 泛型 + * @author shadow + * @date 2020-09-04 + */ + public static void registerBean(String beanName, T bean) { + ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext; + context.getBeanFactory().registerSingleton(beanName, bean); + } } diff --git a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java index e7fbaed87..50553751c 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java @@ -10,6 +10,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import javax.swing.*; import java.util.HashMap; import java.util.Map; @@ -18,11 +19,34 @@ import java.util.Map; //@Import(cn.hutool.extra.spring.SpringUtil.class) public class SpringUtilTest { + /** + * 注册bean + * + * 为了保证顺序采用顺序abcdef...形式命名方法 + */ + @Test + public void a() { + Demo2 registerBean = new Demo2(); + registerBean.id = 123; + registerBean.name = "222"; + SpringUtil.registerBean("registerBean", registerBean); + } + + /** + * 验证注册的bean + */ + @Test + public void b() { + Demo2 registerBean = SpringUtil.getBean("registerBean"); + Assert.assertEquals(123, registerBean.id); + Assert.assertEquals("222", registerBean.name); + } + @Test public void getBeanTest(){ final Demo2 testDemo = SpringUtil.getBean("testDemo"); - Assert.assertEquals(12345, testDemo.getId()); - Assert.assertEquals("test", testDemo.getName()); + Assert.assertEquals(12345, testDemo.id); + Assert.assertEquals("test", testDemo.name); } @Test @@ -41,8 +65,8 @@ public class SpringUtilTest { @Bean(name="testDemo") public Demo2 generateDemo() { Demo2 demo = new Demo2(); - demo.setId(12345); - demo.setName("test"); + demo.id = 12345; + demo.name= "test"; return demo; } From f1cc75b64eef128fa745b454f1be8f86ab28ca8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Fri, 4 Sep 2020 11:59:59 +0800 Subject: [PATCH 8/9] =?UTF-8?q?Revert=20"Add:=20SpringUtil.getBean(TypeRef?= =?UTF-8?q?erence)=20=E6=B7=BB=E5=8A=A0Spring=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E9=9D=99=E6=80=81=E6=96=B9=E6=B3=95=EF=BC=8C=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E7=B1=BB=E5=9E=8B=E5=8F=82=E8=80=83=EF=BC=88TypeRefer?= =?UTF-8?q?ence=EF=BC=89=E8=8E=B7=E5=8F=96=E5=B8=A6=E6=B3=9B=E5=9E=8B?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E7=9A=84Bean=EF=BC=8C=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E4=B8=80=E4=B8=AA=E5=B0=8F=E7=9A=84?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 04dd1d67 --- .../hutool/extra/spring/SpringUtilTest.java | 34 ++++--------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java index 50553751c..ed1074771 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java @@ -10,8 +10,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.swing.*; +import java.lang.reflect.Type; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; @RunWith(SpringJUnit4ClassRunner.class) @@ -19,34 +20,11 @@ import java.util.Map; //@Import(cn.hutool.extra.spring.SpringUtil.class) public class SpringUtilTest { - /** - * 注册bean - * - * 为了保证顺序采用顺序abcdef...形式命名方法 - */ - @Test - public void a() { - Demo2 registerBean = new Demo2(); - registerBean.id = 123; - registerBean.name = "222"; - SpringUtil.registerBean("registerBean", registerBean); - } - - /** - * 验证注册的bean - */ - @Test - public void b() { - Demo2 registerBean = SpringUtil.getBean("registerBean"); - Assert.assertEquals(123, registerBean.id); - Assert.assertEquals("222", registerBean.name); - } - @Test public void getBeanTest(){ final Demo2 testDemo = SpringUtil.getBean("testDemo"); - Assert.assertEquals(12345, testDemo.id); - Assert.assertEquals("test", testDemo.name); + Assert.assertEquals(12345, testDemo.getId()); + Assert.assertEquals("test", testDemo.getName()); } @Test @@ -65,8 +43,8 @@ public class SpringUtilTest { @Bean(name="testDemo") public Demo2 generateDemo() { Demo2 demo = new Demo2(); - demo.id = 12345; - demo.name= "test"; + demo.setId(12345); + demo.setName("test"); return demo; } From d72f2ddf279df8d80f6d5cbecadee180de21ea67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E9=9B=A8=E5=A4=9C?= <758366855@qq.com> Date: Fri, 4 Sep 2020 12:01:54 +0800 Subject: [PATCH 9/9] =?UTF-8?q?feat(SpringUtil):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=96=B0=E7=89=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.添加向Spring动态注册Bean的方法 --- .../hutool/extra/spring/SpringUtilTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java index ed1074771..07935e505 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/spring/SpringUtilTest.java @@ -20,6 +20,27 @@ import java.util.Map; //@Import(cn.hutool.extra.spring.SpringUtil.class) public class SpringUtilTest { + /** + * 注册bean + * 方便执行顺序使用abcd...的顺序命名方法 + */ + @Test + public void a() { + Demo2 registerBean = new Demo2(); + registerBean.setId(123); + registerBean.setName("222"); + SpringUtil.registerBean("registerBean", registerBean); + } + + /** + * 验证注册的bean + */ + @Test + public void b() { + Demo2 registerBean = SpringUtil.getBean("registerBean"); + Assert.assertEquals(123, registerBean.getId()); + Assert.assertEquals("222", registerBean.getName()); + } @Test public void getBeanTest(){ final Demo2 testDemo = SpringUtil.getBean("testDemo");