# solon-expression **Repository Path**: opensolon/solon-expression ## Basic Information - **Project Name**: solon-expression - **Description**: Solon 简单求值表达式语言(SnEL) - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: https://solon.noear.org - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2025-05-09 - **Last Updated**: 2025-09-24 ## Categories & Tags **Categories**: utils **Tags**: None ## README


Solon-Expression(SnEL)

Solon 简单求值表达式语言(SnEL)
克制、高效、开放

https://solon.noear.org/article/learn-solon-snel

Ask DeepWiki Maven Apache 2 jdk-8 jdk-11 jdk-17 jdk-21 jdk-25
gitee star github star gitcode star


## 1、描述 Solon 基础插件。为 Solon 提供了一套表达式通用接口。并内置 Solon Expression Language(简称,SnEL)“求值”表达式实现方案。纯 Java 代码实现,零依赖(可用于其它任何框架)。编译后为 40KB 多点儿。 * 运行后,内存比较省(与同类相比) * 只作解析运行(没有编译,没有字节码。不会产生新的隐藏类) 解析后会形成一个表达式“树结构”。可做为中间 DSL,按需二次转换为其它表达式(比如 redis、milvus 的过滤表达式) 主要特点: * 总会输出一个结果(“求值”表达式嘛) * 通过上下文传递变量,只支持对上下文的变量求值(不支持 `new Xxx()`) * 只能有一条表达式语句(即不能有 `;` 号) * 不支持控制运算(即不能有 `if`、`for` 之类的),不能当脚本用。 * 对象字段、属性、方法调用。可多层嵌套,但只支持 `public`(相对更安全些) * 支持模板表达式 如果有脚本需求,可用:Liquor! ## 2、简单示例 你好世界: ```java System.out.println(SnEL.eval("'hello world!'")); ``` `SnEL` 是 `SnelEvaluator.getInstance()` 快捷方式。可以直接使用 SnEL ,也可以按需实例化 SnelEvaluator ## 3、能力说明 | 能力 | 示例 | 备注 | | --------------- | ---------------------- | -------- | | 支持常量获取 | `1`, `'name'`, `true`, `[1,2,3]` | 数字、字符串、布尔、数组 | | 支持变量获取 | `name` | | | 支持字典获取 | `map['name']` | | | 支持集合获取 | `list[0]` | | | 支持对象属性或字段获取 | `user.name`, `user['name']` | 支持`.` 或 `[]` | | 支持对象方法获取 | `order.getUser()`, `list[0].getUser().getName()` | 支持多级嵌套 | | 支持对象静态方法获取 | `Math.add(1, 2)`, `Math.add(a, b)` | 支持多级嵌套 | | 支持优先级小括号 | `(`, `)` | | | 支持算数操作符 | `+`, `-`, `*`, `/`, `%` | 加,减,乘,除,模 | | 支持比较操作符 | `<`, `<=`, `>`, `>=`, `==`, `!=` | 结果为布尔 | | 支持like操作符 | `LIKE`, `NOT LIKE`(在相当于包含) | 结果为布尔 | | 支持in操作符 | `IN`, `NOT IN` | 结果为布尔 | | 支持三元逻辑操作符 | `conditionExpr ? trueExpr: falseExpr` | | | 支持二元逻辑操作符 | `AND`, `OR` | 与,或(兼容 `&&`、`||` ) | | 支持一元逻辑操作符 | `NOT` | 非(兼容 `!` ) | 虚拟变量(root)说明: 当使用 StandardContext 上下文时,支持 `root` 虚拟变量(`SnEL.eval("root == true", new StandardContext(true))`) 关键字须使用全大写(未来还可能会增多): `LIKE`, `NOT LIKE`, `IN`, `NOT IN` ,`AND`, `OR` ,`NOT` 数据类型与符号说明: `1.1F`(单精度)、`1.1D`(双精度)、`1L`(长整型)。`1.1`(双精度)、`1`(整型) 预留特殊符号: `#{ }`, `${ }` ## 4、表达式示例 * 常量与算数表达式 ```java System.out.println(SnEL.eval("1")); System.out.println(SnEL.eval("-1")); System.out.println(SnEL.eval("1 + 1")); System.out.println(SnEL.eval("1 * (1 + 2)")); System.out.println(SnEL.eval("'solon'")); System.out.println(SnEL.eval("true")); System.out.println(SnEL.eval("[1,2,3,-4]")); ``` * 变量,字典,集合获取 ```java Map map = new HashMap<>(); map.put("code", "world"); List list = new ArrayList<>(); list.add(1); Map context = new HashMap<>(); context.put("name", "solon"); context.put("list", list); context.put("map", map); System.out.println(SnEL.eval("name.length()", context)); //顺便调用个函数 System.out.println(SnEL.eval("name.length() > 2 OR true", context)); System.out.println(SnEL.eval("name.length() > 2 ? 'A' : 'B'", context)); System.out.println(SnEL.eval("map['code']", context)); System.out.println(SnEL.eval("list[0]", context)); System.out.println(SnEL.eval("list[0] == 1", context)); ``` * 带优先级的复杂逻辑表达式 ```java Map context = new HashMap<>(); context.put("age", 25); context.put("salary", 4000); context.put("isMarried", false); context.put("label", "aa"); context.put("title", "ee"); context.put("vip", "l3"); String expression = "(((age > 18 AND salary < 5000) OR (NOT isMarried)) AND label IN ['aa','bb'] AND title NOT IN ['cc','dd']) OR vip=='l3'"; System.out.println(SnEL.eval(expression, context)); ``` * 静态函数调用表达式 ```java Map context = new HashMap<>(); context.put("Math", Math.class); System.out.println(SnEL.eval("Math.abs(-5) > 4 ? 'A' : 'B'", context)); ``` ## 5、嵌入对象(仅为示例) ```java Map context = new HashMap<>(); context.put("Solon", Solon.class); context.put("_sysProps", Solon.cfg()); //顺便别的对象(供参考) context.put("_sysEnv", System.getenv()); //顺便用三元表达式,模拟下 if 语法 String expr = "Solon.cfg().getInt('demo.type', 0) > _sysProps.getInt('') ? Solon.context().getBean('logService').log(1) : 0"; System.out.println(SnEL.eval(expr, context)); ``` ## 6、模板表达式 占位符说明 | 接口 | 描述 | | -------- | -------- | | `#{...}` | 求值表达式占位符 | | `${..}` | 属性表达式占位符(参考 Solon.cfg() 的 getByExpr 接口,支持默认值表达) | 应用示例 ```java Map data = new HashMap<>(); data.put("a", 1); data.put("b", 1); StandardContext context = new StandardContext(data); context.properties(Solon.cfg()); //绑定应用属性,支持 ${表过式} SnEL.evalTmpl("sum val is #{a + b}, c prop is ${demo.c:c}"); ``` ## 7、SnEL 快捷方式接口 | 接口 | 描述 | | -------- | -------- | | `parse(...)` | 解析求值表达式 | | `eval(...)` | 评估求值表达式 | | `parseTmpl(...)` | 解析模板表达式 | | `evalTmpl(...)` | 评估模板表达式 | ```java /** * Solon 表达式语言引擎快捷方式(简称,SnEL) */ public interface SnEL { /** * 解析(将文本解析为一个可评估的表达式结构树,可反向转换) */ static Expression parse(String expr, boolean cached) { return SnelEvaluateParser.getInstance().parse(expr, cached); } static Expression parse(String expr) { return parse(expr, true); } /// ///////////////// /** * 评估 * * @param expr 表达式 * @param context 上下文 * @param cached 是否带编译缓存 */ static Object eval(String expr, Function context, boolean cached) { return parse(expr, cached).eval(context); } /** * 评估 * * @param expr 表达式 * @param context 上下文 * @param cached 是否带编译缓存 */ static Object eval(String expr, Map context, boolean cached) { return eval(expr, context::get, cached); } /** * 评估(带编译缓存) * * @param expr 表达式 * @param context 上下文 */ static Object eval(String expr, Function context) { return eval(expr, context, true); } /** * 评估(带编译缓存) * * @param expr 表达式 * @param context 上下文 */ static Object eval(String expr, Map context) { return eval(expr, context, true); } /** * 评估(带编译缓存) * * @param expr 表达式 */ static Object eval(String expr) { return eval(expr, Collections.EMPTY_MAP, true); } /// ///////////////////////////// /** * 上下文中的属性键(用于支持属性表达式) */ static final String CONTEXT_PROPS_KEY = "$PROPS"; /** * 解析模板 */ static Expression parseTmpl(String expr, boolean cached) { return SnelTemplateParser.getInstance().parse(expr, cached); } static Expression parseTmpl(String expr) { return parseTmpl(expr, true); } /// ///////////////// /** * 评估模板 * * @param expr 表达式 * @param context 上下文 * @param cached 是否带编译缓存 */ static String evalTmpl(String expr, Function context, boolean cached) { return parseTmpl(expr, cached).eval(context); } /** * 评估模板 * * @param expr 表达式 * @param context 上下文 * @param cached 是否带编译缓存 */ static String evalTmpl(String expr, Map context, boolean cached) { return evalTmpl(expr, context::get, cached); } /** * 评估模板(带编译缓存) * * @param expr 表达式 * @param context 上下文 */ static String evalTmpl(String expr, Function context) { return evalTmpl(expr, context, true); } /** * 评估模板(带编译缓存) * * @param expr 表达式 * @param context 上下文 */ static String evalTmpl(String expr, Map context) { return evalTmpl(expr, context, true); } /** * 评估模板(带编译缓存) * * @param expr 表达式 */ static String evalTmpl(String expr) { return evalTmpl(expr, Collections.EMPTY_MAP, true); } } ``` ## Solon 项目相关代码仓库 | 代码仓库 | 描述 | |------------------------------------------------------------------|----------------------------------| | [/opensolon/solon](../../../../opensolon/solon) | Solon ,主代码仓库 | | [/opensolon/solon-examples](../../../../opensolon/solon-examples) | Solon ,官网配套示例代码仓库 | | | | | [/opensolon/solon-expression](../../../../opensolon/solon-expression) | Solon Expression ,代码仓库 | | [/opensolon/solon-flow](../../../../opensolon/solon-flow) | Solon Flow ,代码仓库 | | [/opensolon/solon-ai](../../../../opensolon/solon-ai) | Solon Ai ,代码仓库 | | [/opensolon/solon-cloud](../../../../opensolon/solon-cloud) | Solon Cloud ,代码仓库 | | [/opensolon/solon-admin](../../../../opensolon/solon-admin) | Solon Admin ,代码仓库 | | [/opensolon/solon-jakarta](../../../../opensolon/solon-jakarta) | Solon Jakarta ,代码仓库(base java21) | | [/opensolon/solon-integration](../../../../opensolon/solon-integration) | Solon Integration ,代码仓库 | | | | | [/opensolon/solon-gradle-plugin](../../../../opensolon/solon-gradle-plugin) | Solon Gradle ,插件代码仓库 | | [/opensolon/solon-idea-plugin](../../../../opensolon/solon-idea-plugin) | Solon Idea ,插件代码仓库 | | [/opensolon/solon-vscode-plugin](../../../../opensolon/solon-vscode-plugin) | Solon VsCode ,插件代码仓库 |