feat(condition): CONDITION 判断方式二选一——EXPRESSION 内置 Aviator 表达式(沙箱)+ SERVICE 原口径;JudgeBody 补 submitterId
- ExpressionEvaluator:Aviator 5.4.3 沙箱(FEATURE_SET 只留 If、ALLOWED_CLASS_SET 空=禁类访问/反射)、编译缓存、 顶层变量缺失抛错挂起(Aviator 缺失变量按 nil 且 nil 视作最小值,<= 兜底出口会静默放行——宁挂起不误放行) - ConditionRouteService.decide 分流:EXPRESSION 按出边顺序取首个 true(逐边结果摘要落 raw_response), 全 false/异常挂起沿用 SERVICE 纪律(route_log outlet=NULL + EXPRESSION 常量 + 告警 + 管理端重跑) - DefValidator 发布期分层校验:EXPRESSION 出口缺条件/语法错/违禁表达式硬拦;表单变量放行(运行时核对); 内置变量疑似拼错 warn;judgeMode 非法值拦 - /admin/router/eval 调试端点(同一求值核心,不落库不走流程) - 单测 22 新增 + 全量 170 绿;E2E 18/18(发布/分支选路/挂起留痕/重跑/调试)见 local-debug/four-topics-a-e2e.py
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package com.yunhai.flowcenter.engine;
|
||||
|
||||
import com.googlecode.aviator.AviatorEvaluator;
|
||||
import com.googlecode.aviator.AviatorEvaluatorInstance;
|
||||
import com.googlecode.aviator.Expression;
|
||||
import com.googlecode.aviator.Feature;
|
||||
import com.googlecode.aviator.Options;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 条件路由表达式求值核心(2026-10-10 四议题 Phase 4):CONDITION 节点 judgeMode=EXPRESSION 时,
|
||||
* 出边 condition 即 AviatorScript 表达式,按出边定义顺序取首个求值为 true 的出口。
|
||||
* 发布期校验(DefValidator)、运行时(ConditionRouteService)、调试端点(/admin/router/eval)
|
||||
* 共用本类——三处口径天然一致。
|
||||
*
|
||||
* <p><b>沙箱纪律(勿放宽)</b>:FEATURE_SET 只留 If(三元/条件),NewInstance/Module/Use/
|
||||
* Static* 全部不在集合内即禁用;ALLOWED_CLASS_SET=空不可变集 = 禁一切 Java 类访问(反射/静态
|
||||
* 方法/类字面量);表达式只能引用变量与 Aviator 内置纯函数(math/string/seq)。
|
||||
*
|
||||
* <p><b>缺失变量口径(宁挂起不误放行)</b>:顶层变量缺失(拼写错/表单未传)直接抛错由调用方
|
||||
* 挂起——Aviator 的 nil 参与大小比较时视作最小值,{@code x <= n} 这类兜底出口会对缺失字段
|
||||
* <i>静默放行</i>,必须拦住。判空请显式写 {@code x == nil}(嵌套属性缺失走 nil 语义,
|
||||
* {@code form.amount == nil} 可用)。env 中显式为 null 的值仍按 nil 语义求值。
|
||||
*
|
||||
* <p>线程安全:{@link AviatorEvaluatorInstance} 本身线程安全,编译结果带缓存(key=表达式串)。
|
||||
*/
|
||||
public final class ExpressionEvaluator {
|
||||
|
||||
private ExpressionEvaluator() {
|
||||
}
|
||||
|
||||
private static final AviatorEvaluatorInstance INSTANCE = createSandboxed();
|
||||
|
||||
private static AviatorEvaluatorInstance createSandboxed() {
|
||||
AviatorEvaluatorInstance instance = AviatorEvaluator.newInstance();
|
||||
instance.setOption(Options.FEATURE_SET, Feature.asSet(Feature.If));
|
||||
instance.setOption(Options.ALLOWED_CLASS_SET, Collections.emptySet());
|
||||
instance.setOption(Options.NIL_WHEN_PROPERTY_NOT_FOUND, Boolean.TRUE);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 求值(编译缓存复用)。顶层变量缺失直接抛错(调用方挂起)——Aviator 对缺失顶层变量一律
|
||||
* 按 nil 求值且不可配置,而 nil 视作最小值会让 {@code x <= n} 这类兜底出口静默放行。
|
||||
* 嵌套属性(form.amount)缺失走 nil 语义,判空请显式 {@code form.amount == nil}。
|
||||
*
|
||||
* @return 求值结果;调用方仅把 Boolean.TRUE 视为命中(null/非布尔一律不命中——宁挂起不误放行)
|
||||
*/
|
||||
public static Object evaluate(String expression, Map<String, Object> env) {
|
||||
Expression compiled = compile(expression);
|
||||
for (String name : compiled.getVariableNames()) {
|
||||
if (!env.containsKey(name)) {
|
||||
throw new IllegalStateException("表达式变量未提供:" + name
|
||||
+ "(拼写错误或表单未传;宁挂起不误放行,不按 nil 求值)");
|
||||
}
|
||||
}
|
||||
return compiled.execute(env);
|
||||
}
|
||||
|
||||
/** 语法校验/预编译(发布期拦语法错;与运行时走同一编译路径) */
|
||||
public static Expression compile(String expression) {
|
||||
return INSTANCE.compile(expression, true);
|
||||
}
|
||||
|
||||
/** 表达式引用的顶层变量名(发布期"内置变量疑似拼错"提示用) */
|
||||
public static List<String> variableNames(String expression) {
|
||||
return compile(expression).getVariableNames();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user