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