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) * 共用本类——三处口径天然一致。 * *

沙箱纪律(勿放宽):FEATURE_SET 只留 If(三元/条件),NewInstance/Module/Use/ * Static* 全部不在集合内即禁用;ALLOWED_CLASS_SET=空不可变集 = 禁一切 Java 类访问(反射/静态 * 方法/类字面量);表达式只能引用变量与 Aviator 内置纯函数(math/string/seq)。 * *

缺失变量口径(宁挂起不误放行):顶层变量缺失(拼写错/表单未传)直接抛错由调用方 * 挂起——Aviator 的 nil 参与大小比较时视作最小值,{@code x <= n} 这类兜底出口会对缺失字段 * 静默放行,必须拦住。判空请显式写 {@code x == nil}(嵌套属性缺失走 nil 语义, * {@code form.amount == nil} 可用)。env 中显式为 null 的值仍按 nil 语义求值。 * *

线程安全:{@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 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 variableNames(String expression) { return compile(expression).getVariableNames(); } }