From 80f85390e4275f41273f27dfa10fa67d89613cba Mon Sep 17 00:00:00 2001 From: Looly Date: Mon, 28 Sep 2020 19:27:57 +0800 Subject: [PATCH] fix bug --- CHANGELOG.md | 3 +- .../java/cn/hutool/core/util/NumberUtil.java | 135 +++++++++--------- .../java/cn/hutool/script/ScriptUtil.java | 27 +++- .../hutool/script/test/NashornDeepTest.java | 22 +++ .../cn/hutool/script/test/ScriptUtilTest.java | 8 ++ hutool-script/src/test/resources/filter1.js | 6 + 6 files changed, 127 insertions(+), 74 deletions(-) create mode 100644 hutool-script/src/test/java/cn/hutool/script/test/NashornDeepTest.java create mode 100644 hutool-script/src/test/resources/filter1.js diff --git a/CHANGELOG.md b/CHANGELOG.md index dd46e05c9..ec976133c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.4.4 (2020-09-23) +# 5.4.4 (2020-09-28) ### 新特性 * 【core 】 ServiceLoaderUtil改为使用contextClassLoader(pr#183@Gitee) @@ -36,6 +36,7 @@ * 【core 】 修复新建默认TreeSet没有默认比较器导致的问题(issue#1101@Github) * 【core 】 修复Linux下使用Windows路径分隔符导致的解压错误(issue#I1MW0E@Gitee) * 【core 】 修复Word07Writer写出map问题(issue#I1W49R@Gitee) +* 【script 】 修复函数库脚本执行问题 ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java index 2f0f95a5e..bb5e7af11 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java @@ -44,13 +44,13 @@ public class NumberUtil { private static final int DEFAUT_DIV_SCALE = 10; /** - * 0-20对应的阶乘,超过20的阶乘会超过Long.MAX_VALUE - */ - private static final long[] FACTORIALS = new long[]{ - 1L, 1L, 2L, 6L, 24L, 120L, 720L, 5040L, 40320L, 362880L, 3628800L, 39916800L, 479001600L, 6227020800L, - 87178291200L, 1307674368000L, 20922789888000L, 355687428096000L, 6402373705728000L, 121645100408832000L, - 2432902008176640000L}; - + * 0-20对应的阶乘,超过20的阶乘会超过Long.MAX_VALUE + */ + private static final long[] FACTORIALS = new long[]{ + 1L, 1L, 2L, 6L, 24L, 120L, 720L, 5040L, 40320L, 362880L, 3628800L, 39916800L, 479001600L, 6227020800L, + 87178291200L, 1307674368000L, 20922789888000L, 355687428096000L, 6402373705728000L, 121645100408832000L, + 2432902008176640000L}; + /** * 提供精确的加法运算 * @@ -448,7 +448,7 @@ public class NumberUtil { return BigDecimal.ZERO; } - BigDecimal result =new BigDecimal(values[0]); + BigDecimal result = new BigDecimal(values[0]); for (int i = 1; i < values.length; i++) { result = result.multiply(new BigDecimal(values[i])); } @@ -756,13 +756,13 @@ public class NumberUtil { /** * 补充Math.ceilDiv() JDK8中添加了和Math.floorDiv()但却没有ceilDiv() * - * @param v1 被除数 - * @param v2 除数 + * @param v1 被除数 + * @param v2 除数 * @return 两个参数的商 * @since 5.3.3 */ public static int ceilDiv(int v1, int v2) { - return (int)Math.ceil((double)v1 / v2); + return (int) Math.ceil((double) v1 / v2); } // ------------------------------------------------------------------------------------------- round @@ -1430,50 +1430,49 @@ public class NumberUtil { * @return 结果 * @since 4.1.0 */ - public static long factorial(long start, long end) { - // 负数没有阶乘 - if(start < 0 || end < 0) { - throw new IllegalArgumentException(String.format("Factorial start and end both must be >= 0, " + - "but got start=%d, end=%d", start, end)); - } - if (0L == start || start == end) { - return 1L; - } - if (start < end) { - return 0L; - } - return factorialMultiplyAndCheck(start, factorial(start - 1, end)); - } - - /** - * 计算范围阶乘中校验中间的计算是否存在溢出,factorial提前做了负数和0的校验,因此这里没有校验数字的正负 - * @param a 乘数 - * @param b 被乘数 - * @return 如果 a * b的结果没有溢出直接返回,否则抛出异常 - */ - private static long factorialMultiplyAndCheck(long a, long b) { - if (a <= Long.MAX_VALUE / b) { - return a * b; - } - throw new IllegalArgumentException(String.format("Overflow in multiplication: {%d} * {%d}", a, b)); - } + public static long factorial(long start, long end) { + // 负数没有阶乘 + if (start < 0 || end < 0) { + throw new IllegalArgumentException(StrUtil.format("Factorial start and end both must be >= 0, but got start={}, end={}", start, end)); + } + if (0L == start || start == end) { + return 1L; + } + if (start < end) { + return 0L; + } + return factorialMultiplyAndCheck(start, factorial(start - 1, end)); + } - /** - * 计算阶乘 - *

- * n! = n * (n-1) * ... * 2 * 1 - *

- * - * @param n 阶乘起始 - * @return 结果 - */ - public static long factorial(long n) { - if (n < 0 || n > 20) { - throw new IllegalArgumentException(String.format("Factorial must have n >= 0 and n <= 20 for n!, " + - "but got n = %d", n)); - } - return FACTORIALS[(int) n]; - } + /** + * 计算范围阶乘中校验中间的计算是否存在溢出,factorial提前做了负数和0的校验,因此这里没有校验数字的正负 + * + * @param a 乘数 + * @param b 被乘数 + * @return 如果 a * b的结果没有溢出直接返回,否则抛出异常 + */ + private static long factorialMultiplyAndCheck(long a, long b) { + if (a <= Long.MAX_VALUE / b) { + return a * b; + } + throw new IllegalArgumentException(StrUtil.format("Overflow in multiplication: {} * {}", a, b)); + } + + /** + * 计算阶乘 + *

+ * n! = n * (n-1) * ... * 2 * 1 + *

+ * + * @param n 阶乘起始 + * @return 结果 + */ + public static long factorial(long n) { + if (n < 0 || n > 20) { + throw new IllegalArgumentException(StrUtil.format("Factorial must have n >= 0 and n <= 20 for n!, but got n = {}", n)); + } + return FACTORIALS[(int) n]; + } /** * 平方根算法
@@ -1736,11 +1735,11 @@ public class NumberUtil { */ public static boolean equals(BigDecimal bigNum1, BigDecimal bigNum2) { //noinspection NumberEquality - if (bigNum1 == bigNum2){ + if (bigNum1 == bigNum2) { // 如果用户传入同一对象,省略compareTo以提高性能。 return true; } - if (bigNum1==null || bigNum2==null){ + if (bigNum1 == null || bigNum2 == null) { return false; } return 0 == bigNum1.compareTo(bigNum2); @@ -1838,7 +1837,7 @@ public class NumberUtil { * * @param numberArray 数字数组 * @return 最小值 - * @see ArrayUtil#min(Comparable[]) + * @see ArrayUtil#min(Comparable[]) * @since 5.0.8 */ public static BigDecimal min(BigDecimal... numberArray) { @@ -2186,17 +2185,17 @@ public class NumberUtil { public static BigDecimal pow(BigDecimal number, int n) { return number.pow(n); } - - - /** - * 判断一个整数是否是2的幂 - * - * @param n 待验证的整数 - * @return 如果n是2的幂返回true, 反之返回false - */ - public static boolean isPowerOfTwo(long n) { - return (n > 0) && ((n & (n - 1)) == 0); - } + + + /** + * 判断一个整数是否是2的幂 + * + * @param n 待验证的整数 + * @return 如果n是2的幂返回true, 反之返回false + */ + public static boolean isPowerOfTwo(long n) { + return (n > 0) && ((n & (n - 1)) == 0); + } /** * 解析转换数字字符串为int型数字,规则如下: diff --git a/hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java b/hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java index 7c3061dc1..ec59b47ed 100644 --- a/hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java +++ b/hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java @@ -151,7 +151,12 @@ public class ScriptUtil { } /** - * 执行Javascript脚本,返回Invocable + * 执行Javascript脚本,返回Invocable,此方法分为两种情况: + * + *
    + *
  1. 执行的脚本返回值是可执行的脚本方法
  2. + *
  3. 脚本为函数库,则ScriptEngine本身为可执行方法
  4. + *
* * @param script 脚本内容 * @return 执行结果 @@ -159,11 +164,23 @@ public class ScriptUtil { * @since 5.3.6 */ public static Invocable evalInvocable(String script) throws ScriptRuntimeException { - return (Invocable) eval(script); + final ScriptEngine jsEngine = getJsEngine(); + final Object eval; + try { + eval = jsEngine.eval(script); + } catch (ScriptException e) { + throw new ScriptRuntimeException(e); + } + if(eval instanceof Invocable){ + return (Invocable)eval; + } else if(jsEngine instanceof Invocable){ + return (Invocable)jsEngine; + } + throw new ScriptRuntimeException("Script is not invocable !"); } /** - * 执行Javascript脚本 + * 执行有返回值的Javascript脚本 * * @param script 脚本内容 * @return 执行结果 @@ -179,7 +196,7 @@ public class ScriptUtil { } /** - * 执行脚本 + * 执行有返回值的脚本 * * @param script 脚本内容 * @param context 脚本上下文 @@ -196,7 +213,7 @@ public class ScriptUtil { } /** - * 执行脚本 + * 执行有返回值的脚本 * * @param script 脚本内容 * @param bindings 绑定的参数 diff --git a/hutool-script/src/test/java/cn/hutool/script/test/NashornDeepTest.java b/hutool-script/src/test/java/cn/hutool/script/test/NashornDeepTest.java new file mode 100644 index 000000000..d74d87ffe --- /dev/null +++ b/hutool-script/src/test/java/cn/hutool/script/test/NashornDeepTest.java @@ -0,0 +1,22 @@ +package cn.hutool.script.test; + + +import cn.hutool.core.io.resource.ResourceUtil; +import org.junit.Assert; + +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +public class NashornDeepTest { + + public static void main(String[] args) throws ScriptException, NoSuchMethodException { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); + + engine.eval(ResourceUtil.readUtf8Str("filter1.js")); + + final Object filter1 = ((Invocable) engine).invokeFunction("filter1", 1, 2); + Assert.assertFalse((Boolean) filter1); + } +} diff --git a/hutool-script/src/test/java/cn/hutool/script/test/ScriptUtilTest.java b/hutool-script/src/test/java/cn/hutool/script/test/ScriptUtilTest.java index 6fcbf57c3..d0fa8714b 100644 --- a/hutool-script/src/test/java/cn/hutool/script/test/ScriptUtilTest.java +++ b/hutool-script/src/test/java/cn/hutool/script/test/ScriptUtilTest.java @@ -1,7 +1,9 @@ package cn.hutool.script.test; +import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.script.ScriptRuntimeException; import cn.hutool.script.ScriptUtil; +import org.junit.Assert; import org.junit.Test; import javax.script.CompiledScript; @@ -31,6 +33,12 @@ public class ScriptUtilTest { ScriptUtil.eval("print('Script test!');"); } + @Test + public void invokeTest() { + final Object result = ScriptUtil.invoke(ResourceUtil.readUtf8Str("filter1.js"), "filter1", 2, 1); + Assert.assertTrue((Boolean) result); + } + @Test public void pythonTest() throws ScriptException { final ScriptEngine pythonEngine = ScriptUtil.getPythonEngine(); diff --git a/hutool-script/src/test/resources/filter1.js b/hutool-script/src/test/resources/filter1.js new file mode 100644 index 000000000..a059e4772 --- /dev/null +++ b/hutool-script/src/test/resources/filter1.js @@ -0,0 +1,6 @@ +function filter1(a, b) { + if (a > b) { + return a > b; + } + return false; +} \ No newline at end of file