详见: 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数组类型转化成字符串类型, 供java.lang.System.out.println()使用.
PS:jdk6有一个命令行工具:jrunscript
cd到jire的bin目录,默认为javascript语言,可以直接输入单行js脚本测试语法是否正确, 观察输出