由一个js错误想到的.
背景知识:Java 6提供对执行脚本语言的支持,这个支持来自于JSR223规范,对应的包是javax.script。默认情况下,Java 6只支持JavaScript脚本,它底层的实现是Mozilla Rhino,它是个纯Java的JavaScript实现。
详见: http://developer.51cto.com/art/201007/208812.htm昨天运行ant脚本时触发了macros.js里这样一个js error: Uncaught TypeError: Cannot call method 'join' of undefined.
根据错误的line位置, 我查看了这个js
function concat(parts) {
return parts.join('/');}
很难看出来为什么红色这一行会有问题, 但以前没什么没发生呢. 什么地方的改动触发了这个error呢, 我今天的改动只不过是想把下面SilverFabricSDK和DSServer的version和location由4.1.0改为5.0.1, 就这么一个细小的改动跟上面的js有哪门子关系? 看上面js报错的地方实在是没头绪.
<target name="init">
<init />
<require name="sf-common" when="compile-and-runtime" type="jar"
version="${common_rel_ver}" build-number="${common_build_num}" location="${common.gridlib.dir}"/>
<require name="commons-io" when="compile-and-runtime" type="plain-jar"
version="2.0" location="${basedir}/../../common/lib/thirdparty"/>
<require name="json" when="runtime" type="plain-jar"
version="20080701" location="${basedir}/../../common/lib/thirdparty"/>
<require name="SilverFabricSDK" when="compile" type="plain-jar"
version="5.0.1" location="${basedir}/../../common/lib/sf/5.0.1"/>
<require name="DSServer" when="test" type="plain-jar"
version="4.1.0" location="${basedir}/../../common/lib/sf/4.1.0"/>
...
...
...
于是在js中打印一下parts试试看, 到底是个什么东西.
function concat(parts) {
java.lang.System.out.println("**" + parts.toString()); return parts.join('/');
}
在没错误情况下打印会看得更清楚, 于是先把版本号改回4.1.0, 打印的结果显示原来是把location下的jar文件和版本号拼在一起, 拼成${basedir}/../../common/lib/sf/4.1.0/SilverFabricSDK-4.1.0.jar, 如果location下有这个文件就ok, 没有就会出现上面的error. 于是我又去${basedir}/../../common/lib/sf/5.0.1的下面, 发现SilverFabricSDK.jar这个jar原来不含版本号, 换句话说, 跟没本有${basedir}/../../common/lib/sf/5.0.1/SilverFabricSDK-5.0.1.jar
其实真正引起错误原因的位置并不是显示错误的哪一个行, 而是在下面这一个行时, 传入的参数就已经出问题了:
add_element(path, filename, true);由于上面找的${basedir}/../../common/lib/sf/5.0.1/SilverFabricSDK-5.0.1.jar不存在, 所以parts实际的类型是不是期望的字符串数组, 而是布尔类型, 因为
JavaScript 拥有动态类型,换句话说,相同的变量可用作不同的类型. 布尔类型自然没有数组的join()这个方法, 所以报Cannot call method 'join' of undefined.
function add_element(path, parts, required) {
file = new File(concat(parts));
if (required) {
file.exists() || self.fail('File [' + file.getAbsolutePath() + '] does`t not exist');
element = path.createPathElement();
element.setLocation(file);
} else {
if (file.exists()) {
element = path.createPathElement();
element.setLocation(file);
}
}
}
filename = exists([location, name + '-' + relVer + '.jar']) || exists([location, name + '_' + relVer + '.jar']);
add_element(path, filename, true);
最后还有一点补充, 如果这样打印
function concat(parts) {
java.lang.System.out.println(parts); return parts.join('/');
}
会遇到这样的Exception,
D:\cloudteam\SFAMX\bpm-server\container\build.xml:16: javax.script.ScriptExcepti
on: sun.org.mozilla.javascript.internal.EvaluatorException: Cannot convert sun.o
rg.mozilla.javascript.internal.NativeArray@7a1576 to char[] (<Unknown source>#13
9) in <Unknown source> at line number 139
其实本质上还是js类型的问题, 由于parts不出错情况下是js的字符串数组类型, 而java.lang.System.out.println()的参数是java的char[]类型, 这两个类型没法直接直接转化, 所以必须把parts.toString()或者用"+"连接一个字符串类型, 即java.lang.System.out.println("**"+parts); 这样parts才能从js数组类型转化成字符串