
com.moon.runner.RunnerUtil Maven / Gradle / Ivy
package com.moon.runner;
import com.moon.runner.core.ParseUtil;
import java.util.Date;
/**
* 介绍,运行计算表达式工具类,如:
* employee.name
employee.name.length()
*
group.employee.age.doubleValue() + employee.name.length() + 20 * 5 等。
*
* 【 一 】、支持的运算:
*
* 1. 基本运算:+、-、*、/、%;
*
* 2. 位运算:&、|、^、<<、>>、>>>;
*
* 3. 比较运算:==、>、>=、==、<、<=;
*
* 4. 逻辑运算:&&、||、!;
*
* 5. 括号提升优先级:( )
*
* 【 二 】、预定义关键字:null、true、false
*
* 【 三 】、int 数字:12、25 等
*
* 【 四 】、double 数字:20.0、36.5 等
*
* 注意:
* 参与运算的数字只有 int 或 double,
* 如果一个方法调用的返回值是其他类型数字且没有继续参与运算,
* 则可以返回其他类似数字,包括 char
*
* RunnerUtil 中的数字间可以有一个或多个下划线作为方便阅读用的区分,如:
*
* 123_456 == 123456、3_456.789_123 == 3456.789123
*
* 【 五 】、字符串:'string'、"string"
*
* 【 六 】、Map:解析成 HashMap,
*
* Map 的键:null、true、false、int 型数字、double 型数字、字符串;
* 其他所有形式的键均认为是字符串,且不能是表达式;
*
* 类似 JavaScript 中的对象,不同的是 Map 的键支持数字、true 等;
*
* Map 的值支持任意对象;
*
* 声明方式:
* 1. 空 Map 必须包含一个冒号,如:{:}
*
* 2. 带有值的 Map:{key: 'value', null: 1, true: true, false: 2, 'null': null, "true": "string",}
*
* 一个键值对需用 冒号 分割,键值对之间需用 逗号 分割;
* 最后一个键值对后的逗号可有可无。
*
* 【 七 】、List:解析成 ArrayList,
*
* List 的每一项可以是任意值,两个连续逗号之间若没有任何字符会被解析成一个 null 值,如:
*
* 空 List:{}
*
* 带有值的 List:{null, true, false,, 20, 23.5, 'abc', "xyz", ,};
*
* 最后一个逗号可有可无
*
* 【 八 】、静态方法调用符:@ ;
*
* 如:@System.currentTimeMillis() ==== 无参公共静态方法调用;
*
* 说明:
* 静态方法调用只能调用此工具库所包含的类和 JDK 中以下包的静态方法:
*
* {@link java.lang}、 {@link java.util}、 {@link java.lang.reflect}
*
* 目前只能调用最多一个参数的方法,变长参数不完全支持
*
* 【 九 】、实例方法调用,如:
*
* 无参公共实例方法调用:'string'.length();
*
* {0}.getSheet(0) ==== 带有一个参数的公共实例方法调用;
*
* 【 十 】、链式取值和方法调用:employee.name.length()
*
* 【 十一 】、内置函数:@;
* 此工具类内置了一些内置函数,提供一些常用的操作,对于一些基本的操作,
*
* 建议使用函数,而不是静态或实例方法调用;
*
* 函数调用与静态方法调用相同,都是用 “@” 符号标识,如:@map(...),
*
* 不同的是函数命名空间全小写,并且函数优先级高于方法执行;
*
* 内置函数有:
*
* - @map(...):将一组数据按键值列表返回一个 Map,
* - @map.getSheet(Map, keyName):获取 Map 指定值
* - @map.size(Map):返回 Map 的大小;
* - @map.isEmpty(Map)
* - @map.hasKey(Map)
* - @map.hasValue(Map)
*
* - @list(...):将一组数据列表封装成 List
* - @list.getSheet(List, int):获取指定索引值
* - @list.size(List):返回 List 的大小;
* - @list.isEmpty(List):
* - @list.hasIndex(List):
* - @list.hasValue(List):
*
* - @time():返回当前时间毫秒数{@link System#currentTimeMillis()};
* - @time(Object):将对象转换成{@link java.time.LocalDateTime}
* - @time.year():当前年份
* - @time.month():当前月份
* - @time.day():当前月份第几天
* - @time.hour():当前小时数
* - @time.minute():当前分钟数
* - @time.second():当前秒数
*
* - @str(Object):将对象转换成 String {@link Object#toString()}
* - @str.substring(String,index[,index]):{@link String#substring(int, int)}}
* - @str.indexOf(String,String):{@link String#indexOf(int)}
* - @str.contains(String,String):{@link String#contains(CharSequence)}
* - @str.startsWith(String,String[, int]):{@link String#startsWith(String)}
* - @str.endsWith(String,String[, int]):{@link String#endsWith(String)}
* - @str.length(String):{@link String#length()} 返回字符串长度
* - @str.random():{@link com.moon.core.util.RandomStringUtil#next()} 随机字符串
* - @str.random(int):{@link com.moon.core.util.RandomStringUtil#next(int)} 随机字符串
* - @str.random(int, int):{@link com.moon.core.util.RandomStringUtil#next(int, int)} 随机字符串
*
* - @date():返回当前日期{@link java.util.Date}}
* - @date(Object):将对象转换成{@link java.util.Date}}
* - @date.now():返回当前时间毫秒数{@link System#currentTimeMillis()};
* - @date.format(Date, String):格式化日期{@link java.text.DateFormat#format(Date)}}
*
* - @math.double(Object):
* - @math.int(Object):
* - @math.ceil(Number):
* - @math.floor(Number):
* - @math.sin(Number):正弦函数
* - @math.cos(Number):余弦函数
* - @math.tan(Number):正切函数
* - @math.abs(Number):绝对值
* - @math.round(Number):四舍五入
* - @math.pow(Number,Number):幂次方
* - @math.cbrt(Number,Number):
* - @math.sqrt(Number,Number):
* - @math.log(Number):
* - @math.log10(Number):
* - @math.random():随机数
*
* 注意:
* * 静态方法调用只支持部分包下的类,具体见【 八 】
*
* * 方法调用只支持无参方法和只有一个参数的方法,变长参数的方法不完全支持(慎用)
*
* * 基本数据类型只支持 boolean、int、double,没有 char 类型数据,被征用做字符串了
*
* * 没有 char 数据类型,双引号和单引号包裹的都是字符串,
*
* * 默认字符串表达式分隔符:DELIMITERS = {"{{", "}}"}
*
* @author moonsky
*/
public final class RunnerUtil extends ParseUtil {
/**
* @see AssertionError 不可实例化
*/
private RunnerUtil() { super(); }
/**
* 运行简单表达式,形如: 1 + 2 或 'a' + 'b' 等不含有参数的表达式。
*
* 如果 expression 是一个包含参数的表达式,将抛出异常
*
* 实际实现方式:
* {@link RunnerUtil#run(String)}会缓存所有不包含参数表达式的结果,
* 只解析执行一次,并缓存,以后的运行返回第一次缓存的结果
*
* @param expression 字符串表达式
*
* @return
*
* @see Throwable 如果字符串表达式中包含变量
*/
public final static Object run(String expression) { return parse(expression).run(); }
/**
* 计算带有变量复杂表达式,可接受一个参数,形如:
*
* 1 + 2 + key1[0].name === key1 可以是 Map 的 key 或一个实体对象的字段
*
* 或
*
* 'a' + '2' + [0].key.name === 0 是数组或 List 的索引
*
* 等带有参数的表达式
*
* @param expression 字符串表达式
* @param data 表达式运行时变量所引用的数据
*
* @return
*
* @see NullPointerException 如果字符串表达式中包含 data 中没有的变量
*/
public final static Object run(String expression, Object data) { return parse(expression).run(data); }
/**
* 计算带有变量复杂表达式,可接受多个参数,主要与{@link #run(String, Object)}的区别;
*
* 这儿带有的参数可以是 map、collection、数组、Java bean 对象;
*
* 如果存在相同键名,后出现的将会覆盖之前出现的值
*
* 如果数据是 Iterator 对象,可作为字段传入,不可作为直接量传入
*
* @param expression
* @param data
*
* @return
*/
public final static Object runMulti(String expression, Object... data) { return parse(expression).runMulti(data); }
/**
* 运行字符串中的表达式,如:
*
* RunnerUtil.parseRun("1 + 2 = {{1+2}}"); // ====== "1 + 2 = 3"
*
* RunnerUtil.parseRun("中华人民共和国{{'棒棒的'}}"); // ====== "中华人民共和国棒棒的"
*
* 默认分隔符为:${@link #DELIMITERS} === {"{{", "}}"};
* 可包含多个表达式,但不能嵌套包含,也不能交叉嵌套,如下:
*
* 错误示例:"1 + 2 = {{ 1 + {{ 3 + 4 }} + 2 }}"
*
* 正确示例:"1 + 2 = {{ 1 + 2 }} {{ 3 + 4 }}"
*
* 说明:如果字符串中只有一个表达式,并且始末位置分别就是始末分割符,
* 那么这个表达式返回值可以是任意对象,否则只能返回字符串,如:
* RunnerUtil.parseRun("中华人民共和国{{'棒棒的'}}"); // ====== "中华人民共和国棒棒的"
*
* RunnerUtil.parseRun("{{'棒棒的'}}"); // ====== "棒棒的"
*
* RunnerUtil.parseRun("{{1}}"); // ====== 1
*
【注意:】
* 由于花括号 “{}、{:}” 在此工具中可表示 Map 或 List,
* 所以在可能引起边界混淆的地方最好自定义分隔符,如:
*
* 错误示例: {{{'name'}}}
*
* 应该写成: {{ {'name'}[0] }} === 边界处留有空格;
*
* 或: $[{'name'}] === 自定义分隔符;
*
* @param expression 包含插值语法的字符串表达式
*
* @return
*
* @see Throwable 如果字符串表达式中包含变量
*/
public final static Object parseRun(String expression) { return parse(expression, DELIMITERS).run(); }
/**
* 运行字符串中的带变量的表达式,如:
*
* Map data = {"desc": "棒棒的"} // 这是一个 Map
*
* RunnerUtil.parseRun("中华人民共和国{{desc}}", data); // ====== "中华人民共和国棒棒的"
*
* 默认分隔符为:${@link #DELIMITERS} === {"{{", "}}"}
*
* 【注意:】
* 由于花括号 “{}、{:}” 在此工具中可表示 Map 或 List,
* 所以在可能引起边界混淆的地方最好自定义分隔符,如:
*
* 错误示例: {{{'name'}}}
*
* 应该写成: {{ {'name'}[0] }} === 边界处留有空格;
*
* 或: $[{'name'}] === 自定义分隔符;
*
* @param expression 包含插值语法的字符串表达式
* @param data 表达式运行时变量所引用的数据
*
* @return
*
* @see NullPointerException 如果字符串表达式中包含 data 中没有的变量
* @see #parseRun(String)
*/
public final static Object parseRun(String expression, Object data) {
return parse(expression, DELIMITERS).run(data);
}
public final static Object parseRunMulti(String expression, Object... data) {
return parse(expression, DELIMITERS).runMulti(data);
}
/**
* 可自定义分隔符,如:
*
* Map data = {"desc": "棒棒的"} // 这是一个 Map
*
* String[] delimiters = {"${", "}"};
*
* RunnerUtil.parseRun("本草纲目{desc}", delimiters, data); // ====== "本草纲目棒棒的"
*
* 【注意:】同一个字符串中不可包含多种不同的分隔符而运行多次;
*
* 由于花括号 “{}、{:}” 在此工具中可表示 Map 或 List,
* 所以在可能引起边界混淆的地方最好自定义分隔符,如:
*
* 错误示例: {{{'name'}}}
*
* 应该写成: {{ {'name'}[0] }} === 边界处留有空格;
*
* 或: $[{'name'}] === 自定义分隔符;
*
* @param expression 包含插值语法的字符串表达式
* @param delimiters 必须是一个长度不小于 2 包含始末标记的非空字符串,长度大于 2 后面的内容会被忽略
*
* @return
*
* @see Throwable 如果字符串表达式中包含变量
* @see #parseRun(String, String[], Object)
*/
public final static Object parseRun(String expression, String[] delimiters) {
return parse(expression, delimiters).run();
}
/**
* 可自定义分隔符,如:
*
* Map data = {"desc": "棒棒的"} // 这是一个 Map
*
* String[] delimiters = {"${", "}"};
*
* RunnerUtil.parseRun("本草纲目${desc}", delimiters, data); // ====== "本草纲目棒棒的"
*
* 【注意:】同一个字符串中不可包含多种不同的分隔符而运行多次;
*
* 由于花括号 “{}、{:}” 在此工具中可表示 Map 或 List,
* 所以在可能引起边界混淆的地方最好自定义分隔符,如:
*
* 错误示例: {{{'name'}}}
*
* 应该写成: {{ {'name'}[0] }} === 边界处留有空格;
*
* 或: $[{'name'}] === 自定义分隔符;
*
* @param expression 包含插值语法的字符串表达式
* @param delimiters 必须是一个长度不小于 2 包含始末标记的非空字符串,长度大于 2 后面的内容会被忽略
* @param data 表达式运行时变量所引用的数据
*
* @return
*
* @see NullPointerException 如果字符串表达式中包含 data 中没有的变量
* @see #parseRun(String)
*/
public final static Object parseRun(String expression, String[] delimiters, Object data) {
return parse(expression, delimiters).run(data);
}
public final static Object parseRunMulti(String expression, String[] delimiters, Object... data) {
return parse(expression, delimiters).runMulti(data);
}
}