diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/tree/TreeBuilder.java b/hutool-core/src/main/java/org/dromara/hutool/core/tree/TreeBuilder.java index 744915e59..b24cf9a58 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/tree/TreeBuilder.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/tree/TreeBuilder.java @@ -23,6 +23,7 @@ import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.tree.parser.NodeParser; import org.dromara.hutool.core.util.ObjUtil; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -35,7 +36,7 @@ import java.util.Map; public class TreeBuilder implements Builder> { private static final long serialVersionUID = 1L; - private final MapTree root; + private MapTree root; private final Map> idTreeMap; private boolean isBuild; @@ -69,8 +70,17 @@ public class TreeBuilder implements Builder> { * @param config 配置 */ public TreeBuilder(final E rootId, final TreeNodeConfig config) { - root = new MapTree<>(config); - root.setId(rootId); + this(new MapTree(config).setId(rootId)); + } + + /** + * 构造 + * + * @param root 根节点 + * @since 5.8.33 + */ + public TreeBuilder(final MapTree root) { + this.root = root; this.idTreeMap = new LinkedHashMap<>(); } @@ -149,6 +159,41 @@ public class TreeBuilder implements Builder> { return this; } + /** + * 增加节点列表,增加的节点是不带子节点的 + * + * @param list Bean列表 + * @param Bean类型 + * @param nodeParser 节点转换器,用于定义一个Bean如何转换为Tree节点 + * @return this + */ + public TreeBuilder append(final Iterable list, final NodeParser nodeParser) { + checkBuilt(); + + final TreeNodeConfig config = this.root.getConfig(); + final Iterator iterator = list.iterator(); + return append(new Iterator>() { + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public MapTree next() { + final MapTree node = new MapTree<>(config); + nodeParser.parse(iterator.next(), node); + + if(ObjUtil.equals(node.getId(), root.getId())){ + // issue#IAUSHR 如果指定根节点存在,直接复用 + TreeBuilder.this.root = node; + return null; + } + + return node; + } + }); + } + /** * 增加节点列表,增加的节点是不带子节点的 * @@ -157,9 +202,8 @@ public class TreeBuilder implements Builder> { */ public TreeBuilder append(final Iterable> trees) { checkBuilt(); - - for (final MapTree tree : trees) { - this.idTreeMap.put(tree.getId(), tree); + if (null != trees) { + append(trees.iterator()); } return this; } @@ -167,25 +211,22 @@ public class TreeBuilder implements Builder> { /** * 增加节点列表,增加的节点是不带子节点的 * - * @param list Bean列表 - * @param Bean类型 - * @param nodeParser 节点转换器,用于定义一个Bean如何转换为Tree节点 + * @param iterator 节点列表 * @return this */ - public TreeBuilder append(final List list, final NodeParser nodeParser) { + public TreeBuilder append(final Iterator> iterator) { checkBuilt(); - final TreeNodeConfig config = this.root.getConfig(); - final Map> map = new LinkedHashMap<>(list.size(), 1); - MapTree node; - for (final T t : list) { - node = new MapTree<>(config); - nodeParser.parse(t, node); - map.put(node.getId(), node); + MapTree tree; + while (iterator.hasNext()) { + tree = iterator.next(); + if(null != tree){ + this.idTreeMap.put(tree.getId(), tree); + } } - return append(map); - } + return this; + } /** * 重置Builder,实现复用 diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/tree/TreeUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/tree/TreeUtil.java index 7437b343e..b86e0f823 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/tree/TreeUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/tree/TreeUtil.java @@ -41,7 +41,7 @@ public class TreeUtil { * @return {@link MapTree} * @since 5.7.2 */ - public static MapTree buildSingle(final List> list) { + public static MapTree buildSingle(final Iterable> list) { return buildSingle(list, 0); } @@ -51,7 +51,7 @@ public class TreeUtil { * @param list 源数据集合 * @return List */ - public static List> build(final List> list) { + public static List> build(final Iterable> list) { return build(list, 0); } @@ -65,7 +65,7 @@ public class TreeUtil { * @return {@link MapTree} * @since 5.7.2 */ - public static MapTree buildSingle(final List> list, final E parentId) { + public static MapTree buildSingle(final Iterable> list, final E parentId) { return buildSingle(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>()); } @@ -77,7 +77,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 Iterable> list, final E parentId) { return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>()); } @@ -93,7 +93,7 @@ public class TreeUtil { * @return {@link MapTree} * @since 5.7.2 */ - public static MapTree buildSingle(final List list, final E parentId, final NodeParser nodeParser) { + public static MapTree buildSingle(final Iterable list, final E parentId, final NodeParser nodeParser) { return buildSingle(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, nodeParser); } @@ -107,7 +107,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 Iterable list, final E parentId, final NodeParser nodeParser) { return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, nodeParser); } @@ -122,7 +122,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 Iterable list, final E rootId, final TreeNodeConfig treeNodeConfig, final NodeParser nodeParser) { return buildSingle(list, rootId, treeNodeConfig, nodeParser).getChildren(); } @@ -139,7 +139,7 @@ public class TreeUtil { * @return {@link MapTree} * @since 5.7.2 */ - public static MapTree buildSingle(final List list, final E rootId, final TreeNodeConfig treeNodeConfig, final NodeParser nodeParser) { + public static MapTree buildSingle(final Iterable list, final E rootId, final TreeNodeConfig treeNodeConfig, final NodeParser nodeParser) { return TreeBuilder.of(rootId, treeNodeConfig) .append(list, nodeParser).build(); } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/tree/IssueIAUSHRTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/tree/IssueIAUSHRTest.java new file mode 100644 index 000000000..574d8c318 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/tree/IssueIAUSHRTest.java @@ -0,0 +1,58 @@ +package org.dromara.hutool.core.tree; + +import lombok.Data; +import org.dromara.hutool.core.tree.parser.NodeParser; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class IssueIAUSHRTest { + @Test + void buildSingleTest() { + final List list= new ArrayList<>(); + TestDept sysDept = new TestDept(); + sysDept.setDeptId(1L); + sysDept.setDeptName("A"); + sysDept.setParentId(null); + list.add(sysDept); + + sysDept = new TestDept(); + sysDept.setDeptId(2L); + sysDept.setDeptName("B"); + sysDept.setParentId(1L); + list.add(sysDept); + + sysDept = new TestDept(); + sysDept.setDeptId(3L); + sysDept.setDeptName("C"); + sysDept.setParentId(1L); + list.add(sysDept); + + final TreeNodeConfig treeNodeConfig = new TreeNodeConfig(); + treeNodeConfig.setIdKey("deptId"); + treeNodeConfig.setNameKey("deptName"); + treeNodeConfig.setParentIdKey("parentId"); + + final NodeParser nodeParser= (dept, tree) -> + tree.setId(dept.getDeptId()) + .setParentId(dept.getParentId()) + .setName(dept.getDeptName()); + + final MapTree longTree = TreeUtil.buildSingle(list, 1L, treeNodeConfig, nodeParser); + + assertEquals("A", longTree.getName()); + assertEquals(2, longTree.getChildren().size()); + assertEquals("B", longTree.getChildren().get(0).getName()); + assertEquals("C", longTree.getChildren().get(1).getName()); + } + + @Data + public static class TestDept { + private Long deptId; + private String deptName; + private Long parentId; + } +}