From 0cab2240ce6eeea5f511461b4b038ed9ce2b3750 Mon Sep 17 00:00:00 2001
From: jiangw <39796328+b6688c@users.noreply.github.com>
Date: Sat, 11 Nov 2023 09:24:03 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=A0=91=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E7=BB=93=E6=9E=84=E5=8F=8A=E5=85=B6=E7=9B=B8=E5=85=B3?=
=?UTF-8?q?=E6=93=8D=E4=BD=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 2 +
.../tree}/BreadthTraversalMode.java | 11 +-
.../tree}/DeepTraversalMode.java | 11 +-
.../datastructure/tree/DefaultElement.java | 62 +++++++++
.../datastructure/tree/DefaultExpand.java | 15 +++
.../uno/core/datastructure/tree/Element.java | 124 ++++++++++++++++++
.../uno/core/datastructure/tree/Expand.java | 23 ++++
.../tree}/NoneTraversalMode.java | 4 +-
.../core/datastructure/tree}/Traversal.java | 2 +-
.../datastructure/tree}/TraversalElement.java | 11 +-
.../datastructure/tree}/TraversalMode.java | 2 +-
.../core/datastructure/tree/TreeSupport.java | 102 ++++++++++++++
.../uno/core/datastructure/tree}/Visitor.java | 2 +-
.../cc/allio/uno/core/util/ClassUtils.java | 43 +++---
.../util/template/ExpressionTemplate.java | 28 +---
.../datastructure/tree/TreeSupportTest.java | 29 ++++
.../uno/rule/api/vistor/AttrElement.java | 44 ++++++-
.../api/vistor/DefaultCompilationRule.java | 24 ++--
.../cc/allio/uno/rule/api/vistor/Element.java | 77 -----------
.../uno/rule/api/vistor/GroupElement.java | 4 +-
.../uno/rule/api/vistor/LiteralElement.java | 20 +++
.../api/vistor/LiteralTraversalElement.java | 6 +
.../allio/uno/rule/api/vistor/LogicGroup.java | 93 ++++++++-----
.../uno/rule/drools/DroolsRuleManager.java | 4 +
.../visitor/DefaultCompilationRuleTest.java | 2 +-
25 files changed, 532 insertions(+), 213 deletions(-)
rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/BreadthTraversalMode.java (74%)
rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/DeepTraversalMode.java (73%)
create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultElement.java
create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultExpand.java
create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Element.java
create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Expand.java
rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/NoneTraversalMode.java (77%)
rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/Traversal.java (84%)
rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/TraversalElement.java (73%)
rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/TraversalMode.java (96%)
create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TreeSupport.java
rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/Visitor.java (84%)
create mode 100644 uno-core/src/test/java/cc/allio/uno/core/datastructure/tree/TreeSupportTest.java
delete mode 100644 uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Element.java
create mode 100644 uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralElement.java
create mode 100644 uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralTraversalElement.java
diff --git a/pom.xml b/pom.xml
index da4808a3..d2bc20de 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,12 +10,14 @@
1.1.5.RELEASE
构建大型应用需要的基本能力 --- all in one
https://github.com/b6688c/uno
+
j.x
jiangw1027@gmail.com
+
uno-bom
uno-core
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/BreadthTraversalMode.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/BreadthTraversalMode.java
similarity index 74%
rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/BreadthTraversalMode.java
rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/BreadthTraversalMode.java
index a391583f..0f9f10bd 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/BreadthTraversalMode.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/BreadthTraversalMode.java
@@ -1,4 +1,4 @@
-package cc.allio.uno.rule.api.vistor;
+package cc.allio.uno.core.datastructure.tree;
import cc.allio.uno.core.util.CollectionUtils;
@@ -6,7 +6,7 @@
import java.util.Queue;
/**
- * 广度优先
+ * 树广度优先
*
* @author jiangwei
* @date 2023/4/27 09:17
@@ -14,9 +14,6 @@
*/
public class BreadthTraversalMode implements TraversalMode {
- BreadthTraversalMode() {
- }
-
@Override
public void doTraversal(TraversalElement e, Visitor visitor) {
Queue bfsQueue = new LinkedList<>();
@@ -24,8 +21,8 @@ public void doTraversal(TraversalElement e, Visitor visitor) {
while (!bfsQueue.isEmpty()) {
TraversalElement element = bfsQueue.poll();
element.doAccept(visitor);
- if (CollectionUtils.isNotEmpty(element.getChildrens())) {
- element.getChildrens().forEach(bfsQueue::offer);
+ if (CollectionUtils.isNotEmpty(element.getChildren())) {
+ element.getChildren().forEach(chd -> bfsQueue.offer((TraversalElement) chd));
}
}
}
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DeepTraversalMode.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DeepTraversalMode.java
similarity index 73%
rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DeepTraversalMode.java
rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DeepTraversalMode.java
index dd70bb15..ae431419 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DeepTraversalMode.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DeepTraversalMode.java
@@ -1,4 +1,4 @@
-package cc.allio.uno.rule.api.vistor;
+package cc.allio.uno.core.datastructure.tree;
import cc.allio.uno.core.util.CollectionUtils;
@@ -15,15 +15,12 @@
*/
public class DeepTraversalMode implements TraversalMode {
- DeepTraversalMode() {
- }
-
@Override
public void doTraversal(TraversalElement e, Visitor visitor) {
// 深度优先
Deque dfsStack = new ArrayDeque<>();
dfsStack.push(e);
- List childrens = e.getChildrens();
+ List childrens = e.getChildren();
deepAccept(childrens, dfsStack);
while (!dfsStack.isEmpty()) {
TraversalElement element = dfsStack.pollLast();
@@ -31,10 +28,10 @@ public void doTraversal(TraversalElement e, Visitor visitor) {
}
}
- private void deepAccept(List childrens, Deque dfsStack) {
+ private void deepAccept(List extends TraversalElement> childrens, Deque dfsStack) {
if (CollectionUtils.isNotEmpty(childrens)) {
childrens.forEach(dfsStack::offerLast);
- childrens.forEach(e -> deepAccept(e.getChildrens(), dfsStack));
+ childrens.forEach(e -> deepAccept(e.getChildren(), dfsStack));
}
}
diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultElement.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultElement.java
new file mode 100644
index 00000000..c4f17b86
--- /dev/null
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultElement.java
@@ -0,0 +1,62 @@
+package cc.allio.uno.core.datastructure.tree;
+
+import com.google.common.collect.Lists;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 默认树结点
+ *
+ * @author j.x
+ * @date 2023/11/9 11:36
+ * @since 1.1.5
+ */
+@Getter
+public class DefaultElement extends TraversalElement {
+
+ private final Serializable id;
+ @Setter
+ private int depth;
+
+ @Setter
+ private Element parent;
+
+ private final List children;
+
+ public DefaultElement(@NonNull Serializable id) {
+ this.id = id;
+ this.children = Lists.newArrayList();
+ }
+
+ public DefaultElement(@NonNull Serializable id, int depth) {
+ this.id = id;
+ this.depth = depth;
+ this.children = Lists.newArrayList();
+ }
+
+ @Override
+ public boolean isLeaf() {
+ return children.isEmpty();
+ }
+
+ @Override
+ public void setChildren(List children) {
+ clearChildren();
+ this.children.addAll(children);
+ }
+
+ @Override
+ public void addChildren(Element element) {
+ children.add(element);
+ }
+
+ @Override
+ public void clearChildren() {
+ children.clear();
+ }
+
+}
diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultExpand.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultExpand.java
new file mode 100644
index 00000000..e3b4f334
--- /dev/null
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultExpand.java
@@ -0,0 +1,15 @@
+package cc.allio.uno.core.datastructure.tree;
+
+import java.io.Serializable;
+
+public record DefaultExpand(Serializable id, Serializable parentId) implements Expand {
+ @Override
+ public Serializable getId() {
+ return id;
+ }
+
+ @Override
+ public Serializable getParentId() {
+ return parentId;
+ }
+}
diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Element.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Element.java
new file mode 100644
index 00000000..c9f6aca9
--- /dev/null
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Element.java
@@ -0,0 +1,124 @@
+package cc.allio.uno.core.datastructure.tree;
+
+import cc.allio.uno.core.StringPool;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 节点类型分为两种:
+ *
+ * - group 节点
+ * - attr 节点
+ *
+ *
+ * @author jiangwei
+ * @date 2023/4/26 11:31
+ * @since 1.1.4
+ */
+public interface Element extends Serializable {
+
+ Element ROOT_SENTINEL = new DefaultElement(-1, -1);
+
+ /**
+ * 定义根节点
+ */
+ int ROOT_NODE = 0;
+
+ /**
+ * 获取树的标识
+ */
+ Serializable getId();
+
+ /**
+ * 获取节点所在的深度
+ *
+ * @return level
+ */
+ int getDepth();
+
+ /**
+ * 设置树的层级
+ */
+ void setDepth(int depth);
+
+ /**
+ * 获取当前树的路径
+ *
+ * @return a.b.c以'.'来切分路径标识
+ */
+ default String getPath() {
+ return getParent() != null ? getParent().getPath() + StringPool.ORIGIN_DOT + getId() : String.valueOf(getId());
+ }
+
+ /**
+ * 获取父节点
+ *
+ * @return Element
+ */
+ T getParent();
+
+ /**
+ * 设置父节点
+ *
+ * @param parent parent node
+ */
+ void setParent(T parent);
+
+ /**
+ * 是否为根节点
+ *
+ * @return true 是 false 否
+ */
+ default boolean isRoot() {
+ return getDepth() == ROOT_NODE;
+ }
+
+ /**
+ * 是否为叶子节点
+ *
+ * @return true 是 false 否
+ */
+ boolean isLeaf();
+
+ /**
+ * 获取子节点
+ *
+ * @return element list
+ */
+ List getChildren();
+
+ /**
+ * 添加子结点
+ */
+ void addChildren(T element);
+
+ /**
+ * 覆盖并设置子结点
+ *
+ * @param children children
+ */
+ void setChildren(List children);
+
+ /**
+ * 清除children数据
+ */
+ void clearChildren();
+
+ /**
+ * 访问器模式访问每一个节点。默认实现为深度优先原则
+ *
+ * @param visitor visitor
+ */
+ default void accept(Visitor visitor) {
+ accept(visitor, Traversal.NONE);
+ }
+
+ /**
+ * 访问器模式访问每一个节点。默认实现为深度优先原则
+ *
+ * @param visitor visitor
+ * @param traversal 遍历原则
+ */
+ void accept(Visitor visitor, Traversal traversal);
+}
diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Expand.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Expand.java
new file mode 100644
index 00000000..2f2c8eb0
--- /dev/null
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Expand.java
@@ -0,0 +1,23 @@
+package cc.allio.uno.core.datastructure.tree;
+
+import java.io.Serializable;
+
+/**
+ * 树平展结点
+ *
+ * @author j.x
+ * @date 2023/11/9 11:32
+ * @since 1.1.5
+ */
+public interface Expand {
+
+ /**
+ * 获取当前结点的标识
+ */
+ Serializable getId();
+
+ /**
+ * 获取父节点标识
+ */
+ Serializable getParentId();
+}
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/NoneTraversalMode.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/NoneTraversalMode.java
similarity index 77%
rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/NoneTraversalMode.java
rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/NoneTraversalMode.java
index c95988d7..5cbe5ae3 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/NoneTraversalMode.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/NoneTraversalMode.java
@@ -1,4 +1,4 @@
-package cc.allio.uno.rule.api.vistor;
+package cc.allio.uno.core.datastructure.tree;
/**
* 优先访问枝干
@@ -14,7 +14,7 @@ public class NoneTraversalMode implements TraversalMode {
@Override
public void doTraversal(TraversalElement e, Visitor visitor) {
e.doAccept(visitor);
- e.getChildrens().forEach(c -> c.accept(visitor, getMode()));
+ e.getChildren().forEach(c -> c.accept(visitor, getMode()));
}
@Override
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Traversal.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Traversal.java
similarity index 84%
rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Traversal.java
rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Traversal.java
index 8736863b..a6cec248 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Traversal.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Traversal.java
@@ -1,4 +1,4 @@
-package cc.allio.uno.rule.api.vistor;
+package cc.allio.uno.core.datastructure.tree;
/**
* 规则树遍历方式
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalElement.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalElement.java
similarity index 73%
rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalElement.java
rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalElement.java
index 025681ed..c489d14c 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalElement.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalElement.java
@@ -1,6 +1,4 @@
-package cc.allio.uno.rule.api.vistor;
-
-import java.util.*;
+package cc.allio.uno.core.datastructure.tree;
/**
* 遍历元素原则实现.{@link Traversal}
@@ -16,13 +14,6 @@ public void accept(Visitor visitor, Traversal traversal) {
TraversalMode.get(traversal).doTraversal(this, visitor);
}
- /**
- * 获取子节点
- *
- * @return element list
- */
- protected abstract List getChildrens();
-
/**
* 子类可以继承实现,默认调用访问访问当前元数据
*
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalMode.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalMode.java
similarity index 96%
rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalMode.java
rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalMode.java
index 2d2f70fe..36a218e4 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalMode.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalMode.java
@@ -1,4 +1,4 @@
-package cc.allio.uno.rule.api.vistor;
+package cc.allio.uno.core.datastructure.tree;
import cc.allio.uno.core.exception.Exceptions;
diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TreeSupport.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TreeSupport.java
new file mode 100644
index 00000000..9b9385bd
--- /dev/null
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TreeSupport.java
@@ -0,0 +1,102 @@
+package cc.allio.uno.core.datastructure.tree;
+
+import com.google.common.collect.Lists;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 提供树相关操作
+ *
+ * @author j.x
+ * @date 2023/11/9 11:34
+ * @since 1.1.5
+ */
+public class TreeSupport {
+
+
+ /**
+ * @see #treeify(List, Function)
+ */
+ public static List treeify(List expandTrees) {
+ return (List) treeify(expandTrees, e -> new DefaultElement(e.getId()));
+ }
+
+ /**
+ * 把平展的树转换为具有层次性的树。
+ * 算法明细如下:
+ *
+ * - 构建已{@link Element#getId()}为key的散列表结构
+ * - 循环{@link Expand}列表,每一次循环根据散列表结构找到对应父与当前{@link Element}的结构,然后进行添加
+ *
+ * 时间复杂度将会是O(n)
+ *
+ * @param expandTrees 平展的树
+ * @param treeFunc 平展结构转换为树结构
+ * @param 继承于{@link Expand}的泛型
+ * @param 继承于{@link Element}的泛型
+ * @return hierarchy filter expand tree depth == 0的结点
+ */
+ public static List treeify(List expandTrees, Function treeFunc) {
+ // transfer expand id must not null
+ Map idElement =
+ expandTrees.stream()
+ .map(treeFunc)
+ .collect(Collectors.toMap(Element::getId, e -> e));
+
+ // 已散列表为基础循环设置添加子结点
+ for (T e : expandTrees) {
+ Serializable parentId = e.getParentId();
+ R parent = idElement.get(parentId);
+ if (parent != null) {
+ Serializable id = e.getId();
+ R children = idElement.get(id);
+ children.setDepth(parent.getDepth() + 1);
+ parent.addChildren(children);
+ }
+ }
+
+ // 返回根结点数据
+ return idElement.values()
+ .stream()
+ .filter(e -> e.getDepth() == Element.ROOT_NODE)
+ .toList();
+ }
+
+
+ /**
+ * @see #expand(List, Function)
+ */
+ public static List expand(List forest) {
+ return (List) expand(forest, (r) -> new DefaultExpand(r.getId(), r.getParent() != null ? r.getParent().getId() : null));
+ }
+
+ /**
+ * 把树结构进行平展化。
+ * 采取树访问者模式
+ *
+ * @param forest 树
+ * @param expandFunc 树结构展缓为平展结构
+ * @param 继承于{@link Expand}的泛型
+ * @param 继承于{@link Element}的泛型
+ * @return expand
+ */
+ public static List expand(List forest, Function expandFunc) {
+ List expands = Lists.newArrayList();
+ try {
+ Element.ROOT_SENTINEL.setChildren(forest);
+ Element.ROOT_SENTINEL.accept(e -> {
+ // 忽略哨兵结点
+ if (!Element.ROOT_SENTINEL.equals(e)) {
+ expands.add(expandFunc.apply((R) e));
+ }
+ });
+ } finally {
+ Element.ROOT_SENTINEL.clearChildren();
+ }
+ return expands;
+ }
+}
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Visitor.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Visitor.java
similarity index 84%
rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Visitor.java
rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Visitor.java
index 27a2bea3..7e34a8b2 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Visitor.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Visitor.java
@@ -1,4 +1,4 @@
-package cc.allio.uno.rule.api.vistor;
+package cc.allio.uno.core.datastructure.tree;
/**
* 树节点访问器
diff --git a/uno-core/src/main/java/cc/allio/uno/core/util/ClassUtils.java b/uno-core/src/main/java/cc/allio/uno/core/util/ClassUtils.java
index 62483a6b..1b81ea4a 100644
--- a/uno-core/src/main/java/cc/allio/uno/core/util/ClassUtils.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/util/ClassUtils.java
@@ -1,6 +1,7 @@
package cc.allio.uno.core.util;
import cc.allio.uno.core.StringPool;
+import cc.allio.uno.core.exception.Exceptions;
import com.google.common.collect.Lists;
import lombok.NonNull;
import org.springframework.core.annotation.AnnotatedElementUtils;
@@ -13,7 +14,6 @@
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@@ -24,10 +24,6 @@
*/
public class ClassUtils extends org.springframework.util.ClassUtils {
- private ClassUtils() {
-
- }
-
/**
* 获取class对象只有一个的泛型全限定类名
*
@@ -36,13 +32,10 @@ private ClassUtils() {
* @return 返回一个泛型对象或者空字符串
* @throws NullPointerException 当class对象没有泛型时抛出异常
*/
- public static String getSingleGenericClassName(Class extends T> clazz) {
- if (clazz == null) {
- return "";
- }
+ public static String getSingleGenericClassName(@NonNull Class extends T> clazz) {
Type type = clazz.getGenericSuperclass();
- if (type instanceof ParameterizedType) {
- Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
+ if (type instanceof ParameterizedType pt) {
+ Type[] typeArguments = pt.getActualTypeArguments();
if (typeArguments.length == 0) {
throw new NullPointerException(String.format("Target %s can't find generic", clazz.getName()));
}
@@ -62,8 +55,8 @@ public static String[] getMultiGenericClassName(Class> clazz) {
return new String[0];
}
Type type = clazz.getGenericSuperclass();
- if (type instanceof ParameterizedType) {
- Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
+ if (type instanceof ParameterizedType pt) {
+ Type[] typeArguments = pt.getActualTypeArguments();
if (typeArguments.length == 0) {
throw new NullPointerException(String.format("Target %s can't find generic", clazz.getName()));
}
@@ -114,8 +107,8 @@ public static Class> getSingleActualGenericType(Class> clazz) throws ClassNo
return e;
}
});
- if (exceptType instanceof ClassNotFoundException) {
- throw new ClassNotFoundException(((ClassNotFoundException) exceptType).getMessage());
+ if (exceptType instanceof ClassNotFoundException notfound) {
+ throw new ClassNotFoundException(notfound.getMessage());
}
return (Class>) exceptType;
}
@@ -137,8 +130,8 @@ public static Class>[] getMultiActualGenericType(Class> clazz) throws ClassN
return e;
}
});
- if (exceptType instanceof ClassNotFoundException) {
- throw new ClassNotFoundException(((ClassNotFoundException) exceptType).getMessage());
+ if (exceptType instanceof ClassNotFoundException notfound) {
+ throw new ClassNotFoundException(notfound.getMessage());
}
actualTypes.add((Class>) exceptType);
}
@@ -169,7 +162,7 @@ public static Type[] getFieldGenericType(Field field) {
public static Class>[] objectToClass(Object... args) {
return Arrays.stream(args)
.map(Object::getClass)
- .collect(Collectors.toList())
+ .toList()
.toArray(new Class>[]{});
}
@@ -202,16 +195,17 @@ public static Method getMethod(Class> clazz, String targetMethodName, Class>
try {
method = clazz.getDeclaredMethod(targetMethodName, argsClass);
} catch (NoSuchMethodException e2) {
- e2.printStackTrace();
+ throw Exceptions.unchecked(e2);
}
}
if (method == null) {
Set allMethods = new HashSet<>();
allMethods.addAll(Arrays.asList(clazz.getMethods()));
allMethods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
- List targetMethods = allMethods.stream()
- .filter(m -> targetMethodName.equals(m.getName()) && argsClass.length == m.getParameterCount())
- .collect(Collectors.toList());
+ List targetMethods =
+ allMethods.stream()
+ .filter(m -> targetMethodName.equals(m.getName()) && argsClass.length == m.getParameterCount())
+ .toList();
if (CollectionUtils.isNotEmpty(targetMethods)) {
method = targetMethods.get(0);
}
@@ -285,7 +279,7 @@ public static void setAccessible(Field field, boolean flag) {
* @return true 存在 false 不存在
* @deprecated 1.1.4版本后删除,使用{@link AnnotatedElementUtils#hasAnnotation(AnnotatedElement, Class)}
*/
- @Deprecated
+ @Deprecated(since = "1.1.4", forRemoval = true)
public static boolean containsAnnotation(Class> instanceClass, Class annotationType) {
try {
getAnnotation(instanceClass, annotationType);
@@ -425,9 +419,6 @@ public static class InstantiationBuilder {
private Supplier extends I> ifErrorDefaultValue;
private boolean isExcludeNull;
- InstantiationBuilder() {
- }
-
/**
* 添加一个待实例化的Class对象
*
diff --git a/uno-core/src/main/java/cc/allio/uno/core/util/template/ExpressionTemplate.java b/uno-core/src/main/java/cc/allio/uno/core/util/template/ExpressionTemplate.java
index cc960aa8..5c6181f0 100644
--- a/uno-core/src/main/java/cc/allio/uno/core/util/template/ExpressionTemplate.java
+++ b/uno-core/src/main/java/cc/allio/uno/core/util/template/ExpressionTemplate.java
@@ -14,7 +14,7 @@
import java.net.URL;
import java.util.Collections;
import java.util.Map;
-
+
/**
* Express模版。基于模版文件解析内容
*
@@ -82,32 +82,6 @@ default String parseTemplate(String template, String k1, Object v1, String k2, O
return parseTemplate(template, Tuples.of(k1, v1, k2, v2, k3, v3));
}
-
- /**
- * 解析模板。需要指定模板中占位符包含'T1'、'T2'的标识
- *
- * @param template 模板
- * @param v1 模板变量v1
- * @param v2 模板变量v2
- * @return 解析完成的字符串
- */
- default String parseTemplate(String template, Object v1, Object v2) {
- return parseTemplate(template, Tuples.of("T1", v1, "T2", v2));
- }
-
- /**
- * 解析模板。需要指定模板中占位符包含'T1'、'T2'、'T3'的标识
- *
- * @param template 模板
- * @param v1 模板变量v1
- * @param v2 模板变量v2
- * @param v3 模板变量v3
- * @return 解析完成的字符串
- */
- default String parseTemplate(String template, Object v1, Object v2, Object v3) {
- return parseTemplate(template, Tuples.of("T1", v1, "T2", v2, "T3", v3));
- }
-
/**
* 解析模板
*
diff --git a/uno-core/src/test/java/cc/allio/uno/core/datastructure/tree/TreeSupportTest.java b/uno-core/src/test/java/cc/allio/uno/core/datastructure/tree/TreeSupportTest.java
new file mode 100644
index 00000000..d6f68795
--- /dev/null
+++ b/uno-core/src/test/java/cc/allio/uno/core/datastructure/tree/TreeSupportTest.java
@@ -0,0 +1,29 @@
+package cc.allio.uno.core.datastructure.tree;
+
+import cc.allio.uno.core.BaseTestCase;
+import com.google.common.collect.Lists;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+public class TreeSupportTest extends BaseTestCase {
+
+ static List testData = Lists.newArrayList(
+ new DefaultExpand(1, 0),
+ new DefaultExpand(2, 0),
+ new DefaultExpand(3, 0),
+ new DefaultExpand(4, 1),
+ new DefaultExpand(5, 2)
+ );
+
+ @Test
+ void testTreeifyAndExpand() {
+ List treeify = TreeSupport.treeify(testData);
+
+ assertEquals(3, treeify.size());
+
+ List expands = TreeSupport.expand(treeify);
+
+ assertEquals(testData.size(), expands.size());
+ }
+}
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/AttrElement.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/AttrElement.java
index 76be8f72..4d82edf4 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/AttrElement.java
+++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/AttrElement.java
@@ -1,9 +1,13 @@
package cc.allio.uno.rule.api.vistor;
+import cc.allio.uno.core.datastructure.tree.Element;
+import cc.allio.uno.core.exception.Exceptions;
+import cc.allio.uno.core.util.id.IdGenerator;
import cc.allio.uno.rule.api.RuleAttr;
import lombok.Getter;
import lombok.Setter;
+import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -15,10 +19,12 @@
* @date 2023/4/26 11:53
* @since 1.1.4
*/
-public class AttrElement extends TraversalElement implements Element {
+public class AttrElement extends LiteralTraversalElement implements LiteralElement {
+
+ private final Serializable id;
@Getter
- private final GroupElement> parent;
+ private GroupElement> parent;
@Getter
private final RuleAttr ruleAttr;
@@ -27,19 +33,25 @@ public class AttrElement extends TraversalElement implements Element {
*/
@Setter
@Getter
- private int level;
+ private int depth;
public AttrElement(GroupElement> parent, RuleAttr ruleAttr) {
this.parent = parent;
this.ruleAttr = ruleAttr;
if (parent != null) {
- this.level = parent.getLevel() + 1;
+ this.depth = parent.getDepth() + 1;
}
+ this.id = IdGenerator.defaultGenerator().toHex();
}
@Override
- public List getChildrens() {
- return Collections.emptyList();
+ public Serializable getId() {
+ return id;
+ }
+
+ @Override
+ public void setParent(T parent) {
+ this.parent = (GroupElement>) parent;
}
@Override
@@ -47,6 +59,26 @@ public boolean isLeaf() {
return true;
}
+ @Override
+ public List getChildren() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void addChildren(T element) {
+ Exceptions.eee("AttrElement is leaf element, cannot addChildren", UnsupportedOperationException.class);
+ }
+
+ @Override
+ public void setChildren(List children) {
+ Exceptions.eee("AttrElement is leaf element, cannot setChildren", UnsupportedOperationException.class);
+ }
+
+ @Override
+ public void clearChildren() {
+ Exceptions.eee("AttrElement is leaf element, cannot clearChildren", UnsupportedOperationException.class);
+ }
+
@Override
public String getLiteral() {
return ruleAttr.getIndexExpr();
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DefaultCompilationRule.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DefaultCompilationRule.java
index 48c87251..0a2dcdd9 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DefaultCompilationRule.java
+++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DefaultCompilationRule.java
@@ -1,5 +1,7 @@
package cc.allio.uno.rule.api.vistor;
+import cc.allio.uno.core.datastructure.tree.Element;
+import cc.allio.uno.core.datastructure.tree.Traversal;
import cc.allio.uno.rule.api.LogicPredicate;
import cc.allio.uno.rule.api.RuleAttr;
import com.google.common.collect.Lists;
@@ -15,15 +17,11 @@
*/
public class DefaultCompilationRule implements CompilationRule {
- DefaultCompilationRule() {
-
- }
-
@Override
public GroupElement> treeifyBin(List ruleItems) {
// 根节点为 AND group
LogicGroup root = new LogicGroup(null, LogicPredicate.AND);
- root.setLevel(Element.ROOT_NODE);
+ root.setDepth(Element.ROOT_NODE);
// 获取第一个节点创建遍历表达式
LogicGroup p = null;
for (RuleAttr item : ruleItems) {
@@ -46,7 +44,7 @@ public GroupElement> treeifyBin(List ruleItems) {
} else if (p.getLogic() == LogicPredicate.OR) {
if (item.getLogic() == LogicPredicate.AND) {
// 放入 and group 中
- List attrElement = p.getAttrElement();
+ List attrElement = p.getAttrElement();
p.clearAttrElement();
// 规则项重组为and节点
LogicGroup n = new LogicGroup(p, LogicPredicate.AND);
@@ -72,12 +70,12 @@ private void buildTreeLevel(GroupElement> root) {
int level = Element.ROOT_NODE;
Element parent = e.getParent();
if (parent != null) {
- level = parent.getLevel() + 1;
+ level = parent.getDepth() + 1;
}
- if (e instanceof AttrElement) {
- ((AttrElement) e).setLevel(level);
- } else if (e instanceof LogicGroup) {
- ((LogicGroup) e).setLevel(level);
+ if (e instanceof AttrElement attr) {
+ attr.setDepth(level);
+ } else if (e instanceof LogicGroup logicGroup) {
+ logicGroup.setDepth(level);
}
});
}
@@ -87,8 +85,8 @@ public List expand(GroupElement> tree) {
List ruleAttrs = Lists.newArrayList();
tree.accept(
e -> {
- if (e instanceof AttrElement) {
- RuleAttr ruleAttr = ((AttrElement) e).getRuleAttr();
+ if (e instanceof AttrElement attr) {
+ RuleAttr ruleAttr = attr.getRuleAttr();
ruleAttrs.add(ruleAttr);
}
},
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Element.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Element.java
deleted file mode 100644
index 78e3006c..00000000
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Element.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package cc.allio.uno.rule.api.vistor;
-
-import java.io.Serializable;
-
-/**
- * 定义规则树的节点。
- * 节点类型分为两种:
- *
- * - group 节点
- * - attr 节点
- *
- *
- * @author jiangwei
- * @date 2023/4/26 11:31
- * @since 1.1.4
- */
-public interface Element extends Serializable {
-
- /**
- * 定义根节点
- */
- int ROOT_NODE = 0;
-
- /**
- * 获取节点所在的高度
- *
- * @return level
- */
- int getLevel();
-
- /**
- * 获取父节点
- *
- * @return Element
- */
- Element getParent();
-
- /**
- * 是否为根节点
- *
- * @return true 是 false 否
- */
- default boolean isRoot() {
- return getLevel() == ROOT_NODE;
- }
-
- /**
- * 是否为叶子节点
- *
- * @return true 是 false 否
- */
- boolean isLeaf();
-
- /**
- * 平展开当前规则group 节点规则表达式。
- *
- * @return a == '5' && b == '5'...
- */
- String getLiteral();
-
- /**
- * 访问器模式访问每一个节点。默认实现为深度优先原则
- *
- * @param visitor visitor
- */
- default void accept(Visitor visitor) {
- accept(visitor, Traversal.NONE);
- }
-
- /**
- * 访问器模式访问每一个节点。默认实现为深度优先原则
- *
- * @param visitor visitor
- * @param traversal 遍历原则
- */
- void accept(Visitor visitor, Traversal traversal);
-}
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/GroupElement.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/GroupElement.java
index 448ff17f..02ddffd6 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/GroupElement.java
+++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/GroupElement.java
@@ -1,5 +1,7 @@
package cc.allio.uno.rule.api.vistor;
+import cc.allio.uno.core.datastructure.tree.Element;
+
import java.util.List;
/**
@@ -9,7 +11,7 @@
* @date 2023/4/26 12:04
* @since 1.1.4
*/
-public interface GroupElement extends Element {
+public interface GroupElement extends LiteralElement {
/**
* 添加子节点元素
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralElement.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralElement.java
new file mode 100644
index 00000000..6c402128
--- /dev/null
+++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralElement.java
@@ -0,0 +1,20 @@
+package cc.allio.uno.rule.api.vistor;
+
+import cc.allio.uno.core.datastructure.tree.Element;
+
+/**
+ * 包含规则表达式的结点
+ *
+ * @author j.x
+ * @date 2023/11/9 11:07
+ * @since 1.1.5
+ */
+public interface LiteralElement extends Element {
+
+ /**
+ * 平展开当前规则group 节点规则表达式。
+ *
+ * @return a == '5' && b == '5'...
+ */
+ String getLiteral();
+}
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralTraversalElement.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralTraversalElement.java
new file mode 100644
index 00000000..348bb545
--- /dev/null
+++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralTraversalElement.java
@@ -0,0 +1,6 @@
+package cc.allio.uno.rule.api.vistor;
+
+import cc.allio.uno.core.datastructure.tree.TraversalElement;
+
+public abstract class LiteralTraversalElement extends TraversalElement implements LiteralElement {
+}
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LogicGroup.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LogicGroup.java
index ff8d64c9..ed4f9944 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LogicGroup.java
+++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LogicGroup.java
@@ -1,14 +1,16 @@
package cc.allio.uno.rule.api.vistor;
import cc.allio.uno.core.StringPool;
+import cc.allio.uno.core.datastructure.tree.Element;
import cc.allio.uno.core.util.CollectionUtils;
+import cc.allio.uno.core.util.id.IdGenerator;
import cc.allio.uno.rule.api.LogicPredicate;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.Setter;
+import java.io.Serializable;
import java.util.List;
-import java.util.stream.Collectors;
/**
* logic
@@ -17,93 +19,118 @@
* @date 2023/4/26 11:53
* @since 1.1.4
*/
-public class LogicGroup extends TraversalElement implements GroupElement {
+public class LogicGroup extends LiteralTraversalElement implements GroupElement {
+
+ @Getter
+ private final Serializable id;
@Getter
private final LogicPredicate logic;
- @Setter
+
@Getter
- private GroupElement parent;
- private final List childrens;
+ private GroupElement parent;
+ private List children;
@Setter
@Getter
- private int level;
+ private int depth;
- public LogicGroup(GroupElement parent, LogicPredicate logic) {
+ public LogicGroup(GroupElement parent, LogicPredicate logic) {
this.parent = parent;
this.logic = logic;
- this.childrens = Lists.newArrayList();
+ this.children = Lists.newArrayList();
if (parent != null) {
- this.level = parent.getLevel() + 1;
+ this.depth = parent.getDepth() + 1;
}
+ this.id = IdGenerator.defaultGenerator().toHex();
}
@Override
- public List getChildrens() {
- return childrens;
+ public void setParent(T parent) {
+ this.parent = (GroupElement) parent;
}
@Override
public boolean isLeaf() {
- return childrens.isEmpty();
+ return children.isEmpty();
+ }
+
+ @Override
+ public List getChildren() {
+ return (List) children;
+ }
+
+ @Override
+ public void addChildren(T element) {
+ addElement((LiteralTraversalElement) element);
+ }
+
+ @Override
+ public void setChildren(List children) {
+ clearChildren();
+ this.children.addAll(children);
+ }
+
+ @Override
+ public void clearChildren() {
+ children.clear();
}
@Override
- public boolean addElement(TraversalElement element) {
- return childrens.add(element);
+ public boolean addElement(LiteralTraversalElement element) {
+ return children.add(element);
}
@Override
- public boolean addElements(List elements) {
- return childrens.addAll(elements);
+ public boolean addElements(List elements) {
+ return children.addAll(elements);
}
@Override
- public boolean removeElement(TraversalElement element) {
- return childrens.remove(element);
+ public boolean removeElement(LiteralTraversalElement element) {
+ return children.remove(element);
}
@Override
- public List getGroupElement() {
- return childrens.stream()
+ public List getGroupElement() {
+ return children.stream()
.filter(e -> GroupElement.class.isAssignableFrom(e.getClass()))
- .map(TraversalElement.class::cast)
- .collect(Collectors.toList());
+ .map(LiteralTraversalElement.class::cast)
+ .toList();
}
@Override
- public List getAttrElement() {
- return childrens.stream()
+ public List getAttrElement() {
+ return children.stream()
.filter(e -> AttrElement.class.isAssignableFrom(e.getClass()))
- .map(AttrElement.class::cast)
- .collect(Collectors.toList());
+ .map(LiteralTraversalElement.class::cast)
+ .toList();
}
@Override
public void clearAttrElement() {
- childrens.removeIf(AttrElement.class::isInstance);
+ children.removeIf(AttrElement.class::isInstance);
}
@Override
public String getLiteral() {
- if (isRoot() && CollectionUtils.isNotEmpty(childrens)) {
+ if (isRoot() && CollectionUtils.isNotEmpty(children)) {
// root 节点第一个元素一定时OR
- LogicGroup element = (LogicGroup) childrens.get(0);
+ LogicGroup element = (LogicGroup) children.get(0);
return element.getLiteral();
}
StringBuilder literalExpr = new StringBuilder();
- for (int i = 0; i < childrens.size(); i++) {
- TraversalElement children = childrens.get(i);
+ for (int i = 0; i < children.size(); i++) {
+ LiteralTraversalElement children = (LiteralTraversalElement) this.children.get(i);
String literal = children.getLiteral();
// 构建 a = xxx && xxx 或者 a = xx && (b = xx)
literalExpr.append(literal).append(StringPool.SPACE);
- if (i != childrens.size() - 1) {
+ if (i != this.children.size() - 1) {
literalExpr.append(logic.getSm()).append(StringPool.SPACE);
}
}
// 如果只有一个children 则不进行,否则添加 '(' ')'
- if (childrens.size() == 1) {
+ if (children.size() == 1) {
return literalExpr.toString();
}
literalExpr.insert(0, StringPool.LEFT_BRACKET);
diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/drools/DroolsRuleManager.java b/uno-rule/src/main/java/cc/allio/uno/rule/drools/DroolsRuleManager.java
index a2e966eb..425968cb 100644
--- a/uno-rule/src/main/java/cc/allio/uno/rule/drools/DroolsRuleManager.java
+++ b/uno-rule/src/main/java/cc/allio/uno/rule/drools/DroolsRuleManager.java
@@ -1,5 +1,9 @@
package cc.allio.uno.rule.drools;
+import cc.allio.uno.core.datastructure.tree.Element;
+import cc.allio.uno.rule.api.vistor.GroupElement;
+import cc.allio.uno.core.datastructure.tree.Traversal;
+import cc.allio.uno.core.datastructure.tree.Visitor;
import cc.allio.uno.rule.api.*;
import cc.allio.uno.rule.api.event.RuleContext;
import cc.allio.uno.rule.api.vistor.*;
diff --git a/uno-rule/src/test/java/cc/allio/uno/rule/api/visitor/DefaultCompilationRuleTest.java b/uno-rule/src/test/java/cc/allio/uno/rule/api/visitor/DefaultCompilationRuleTest.java
index bd08c999..3262a89d 100644
--- a/uno-rule/src/test/java/cc/allio/uno/rule/api/visitor/DefaultCompilationRuleTest.java
+++ b/uno-rule/src/test/java/cc/allio/uno/rule/api/visitor/DefaultCompilationRuleTest.java
@@ -2,7 +2,7 @@
import cc.allio.uno.rule.api.vistor.CompilationRule;
import cc.allio.uno.rule.api.vistor.GroupElement;
-import cc.allio.uno.rule.api.vistor.Traversal;
+import cc.allio.uno.core.datastructure.tree.Traversal;
import cc.allio.uno.rule.api.LogicPredicate;
import cc.allio.uno.rule.api.OP;
import cc.allio.uno.rule.api.RuleAttr;