Looly 5 年之前
父节点
当前提交
80f85390e4

+ 2 - 1
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 】     修复函数库脚本执行问题
 
 -------------------------------------------------------------------------------------------------------------
 

+ 68 - 69
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));
-        }
-
-        /**
-         * 计算阶乘
-         * <p>
-         * n! = n * (n-1) * ... * 2 * 1
-         * </p>
-         *
-         * @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];
-        }
+	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));
+	}
+
+	/**
+	 * 计算范围阶乘中校验中间的计算是否存在溢出,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));
+	}
+
+	/**
+	 * 计算阶乘
+	 * <p>
+	 * n! = n * (n-1) * ... * 2 * 1
+	 * </p>
+	 *
+	 * @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];
+	}
 
 	/**
 	 * 平方根算法<br>
@@ -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型数字,规则如下:

+ 22 - 5
hutool-script/src/main/java/cn/hutool/script/ScriptUtil.java

@@ -151,7 +151,12 @@ public class ScriptUtil {
 	}
 
 	/**
-	 * 执行Javascript脚本,返回Invocable
+	 * 执行Javascript脚本,返回Invocable,此方法分为两种情况:
+	 *
+	 * <ol>
+	 *     <li>执行的脚本返回值是可执行的脚本方法</li>
+	 *     <li>脚本为函数库,则ScriptEngine本身为可执行方法</li>
+	 * </ol>
 	 *
 	 * @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 绑定的参数

+ 22 - 0
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);
+	}
+}

+ 8 - 0
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;
@@ -32,6 +34,12 @@ public class ScriptUtilTest {
 	}
 
 	@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();
 		pythonEngine.eval("print('Hello Python')");

+ 6 - 0
hutool-script/src/test/resources/filter1.js

@@ -0,0 +1,6 @@
+function filter1(a, b) {
+    if (a > b) {
+        return a > b;
+    }
+    return false;
+}