JDK6内置了javaScript引擎,用以解决js和java之间的跨界调用。
对于希望开放更加灵活的定制给最终用户的java应用,这是姗姗来迟的福音。
通过在java应用中开放脚本定制给最终用户,可以实现更大程度的灵活性,例如:编写业务规则,甚至是扩充业务函数库。
在我最近编写的一个应用中,采用了上述方式,即:将后台的java编写的功能以javaScript形式发布,
并提供基础javaScript函数库给用户,允许其进行二次开发。
但在具体实施时,还是遇到些许麻烦。书写于此,供后来者借鉴。
我在后台java提供了一个对象,该对象接受HashMap参数传入并执行相应操作,形式如下:
class IDC_Snmp
...
void set(HashMap nvs){
....
}
按照jdk说明文档,
http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/
编写java语句如下:
...
IDC_Snmp idc = new IDC_Snmp();
engine.put("idc",idc);
然后编写js语句如下
idc.set({p1:"v1",p2:"v2"});原本以为engine可以识别js的map类型,并自动匹配java的HashMap形参并调用相应方法,
结果跟踪调试,发现js的map类型到java方法中不能自动匹配为HashMap,而是成为NativeObject。
所以没有获得预期结果。
解决办法之一是:java中增加转换处理,自己编码将NativeObject转换为HashMap。
参考了这篇博文:
http://relive123-yahoo-com-cn.iteye.com/blog/784700
public static Map<String, Object> obj2map(ScriptEngine engine,
Object nativeObject) throws ScriptException, NoSuchMethodException {
Map<String, Object> map = new HashMap<String, Object>();
engine.put("map", map);
engine.put("obj", nativeObject);
String script = " function dosomething(){ "
+ " for (i in obj){ "
+ " map.put(i,obj[i]); "
+ " } " + " } ";
engine.eval(script);
Invocable inv = (Invocable) engine;
inv.invokeFunction("dosomething");
return map;
}
但是总觉得这种方式过于曲折,并不是jdk原生的实现。
因此用了第二种解决办法:就是在javaScript中将map先转为engine可以识别的数组形式,后台的java方法也是以数组形式出现。
相关的代码为:
java部分
class IDC_Snmp
...
void set(String[] pns,Object[]pvs){
...
}
其中pns,pvs分别对应HashMap中多个的Name和Value。
javaScript部分
function set(pvMap){ var pns = []; var pvs = []; for(x in pvMap){ pns[pns.length]=x; pvs[pvs.length]=pvMap[x]; } idc.set(pns,pvs); }这个感觉好些,出问题就该打JDK的板子了!