diff --git a/CHANGELOG.md b/CHANGELOG.md index e157354ee..0b36bb895 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.8.33(2024-09-29) +# 5.8.33(2024-10-02) ### 🐣新特性 * 【core 】 SyncFinisher增加setExecutorService方法(issue#IANKQ1@Gitee) @@ -14,6 +14,7 @@ * 【http 】 HttpRequest增加setFixedContentLength方法(issue#3462@Github) * 【db 】 AbstractDb增加getDs方法(issue#IARKZL@Gitee) * 【db 】 QrCodeUtil添加二维码logo支持配置圆角(pr#3747@Github) +* 【core 】 TreeUtil.buildSingle指定rootId节点存在时,作为根节点(issue#IAUSHR@Gitee) ### 🐞Bug修复 * 【json 】 修复JSONConfig.setDateFormat设置后toBean无效问题(issue#3713@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeBuilder.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeBuilder.java index c8d20eae4..bd243e60e 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeBuilder.java @@ -10,6 +10,7 @@ import cn.hutool.core.util.ObjectUtil; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; /** * 树构建器 @@ -19,7 +20,7 @@ import java.util.Map; public class TreeBuilder implements Builder> { private static final long serialVersionUID = 1L; - private final Tree root; + private Tree root; private final Map> idTreeMap; private boolean isBuild; @@ -53,8 +54,17 @@ public class TreeBuilder implements Builder> { * @param config 配置 */ public TreeBuilder(E rootId, TreeNodeConfig config) { - root = new Tree<>(config); - root.setId(rootId); + this(new Tree(config).setId(rootId)); + } + + /** + * 构造 + * + * @param rootNode 根节点 + * @since 5.8.33 + */ + public TreeBuilder(Tree rootNode) { + this.root = rootNode; this.idTreeMap = new LinkedHashMap<>(); } @@ -157,7 +167,28 @@ public class TreeBuilder implements Builder> { * @return this */ public TreeBuilder append(List list, NodeParser nodeParser) { - return append(list, null, nodeParser); + checkBuilt(); + + final TreeNodeConfig config = this.root.getConfig(); + final E rootId = this.root.getId(); + final Map> map = this.idTreeMap; + Tree node; + for (T t : list) { + node = new Tree<>(config); + nodeParser.parse(t, node); + if (null != rootId && false == rootId.getClass().equals(node.getId().getClass())) { + throw new IllegalArgumentException("rootId type is node.getId().getClass()!"); + } + // issue#IAUSHR 如果指定根节点存在,直接复用 + if(Objects.equals(rootId, node.getId())){ + this.root = node; + }else { + //非根节点 + map.put(node.getId(), node); + } + + } + return append(map); } /** @@ -169,12 +200,14 @@ public class TreeBuilder implements Builder> { * @param nodeParser 节点转换器,用于定义一个Bean如何转换为Tree节点 * @return this * @since 5.8.6 + * @deprecated rootId参数可以不提供,在root节点中直接获取,请使用{@link #append(List, NodeParser)} */ + @Deprecated public TreeBuilder append(List list, E rootId, NodeParser nodeParser) { checkBuilt(); final TreeNodeConfig config = this.root.getConfig(); - final Map> map = new LinkedHashMap<>(list.size(), 1); + final Map> map = this.idTreeMap; Tree node; for (T t : list) { node = new Tree<>(config); @@ -182,7 +215,14 @@ public class TreeBuilder implements Builder> { if (null != rootId && false == rootId.getClass().equals(node.getId().getClass())) { throw new IllegalArgumentException("rootId type is node.getId().getClass()!"); } - map.put(node.getId(), node); + // issue#IAUSHR 如果指定根节点存在,直接复用 + if(Objects.equals(rootId, node.getId())){ + this.root = node; + }else { + //非根节点 + map.put(node.getId(), node); + } + } return append(map); } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java index 69ad8233a..317b1af4c 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java @@ -124,7 +124,7 @@ public class TreeUtil { */ public static Tree buildSingle(List list, E rootId, TreeNodeConfig treeNodeConfig, NodeParser nodeParser) { return TreeBuilder.of(rootId, treeNodeConfig) - .append(list, rootId, nodeParser).build(); + .append(list, nodeParser).build(); } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/tree/IssueIAUSHRTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/tree/IssueIAUSHRTest.java new file mode 100644 index 000000000..979756b5c --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/lang/tree/IssueIAUSHRTest.java @@ -0,0 +1,60 @@ +package cn.hutool.core.lang.tree; + +import cn.hutool.core.lang.tree.parser.NodeParser; +import lombok.Data; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * 如果指定rootId的节点已经存在,直接作为根节点 + */ +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); + + TreeNodeConfig treeNodeConfig = new TreeNodeConfig(); + treeNodeConfig.setIdKey("deptId"); + treeNodeConfig.setNameKey("deptName"); + treeNodeConfig.setParentIdKey("parentId"); + NodeParser nodeParser= (dept, tree) -> + tree.setId(dept.getDeptId()) + .setParentId(dept.getParentId()) + .setName(dept.getDeptName()); + Tree 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; + } +}