在
前面的一篇博客中,我写了怎么在JDK5的环境下使用Rhino的E4X功能,下面要说的是如何在JDK5中使用JSR223的Scripting框架。JSR223即javax.script包是JDK6.0才引入的,并且集成了Rhino作为JavaScript的引擎。不过JDK6集成的Rhino是经过删减功能的,包括主要的E4X没有加入。需要解决的问题有几个:
首先把JSR223的JDK6的实现剥离出来,这个容易,找到JDK6安装目录下面的rt.jar,保留javax.script和com.sun.script两个包,删除其余的文件夹,把此jar命名为jsr223.jar。此外在META-INF下面添加services文件夹,里面添加文件内容为com.sun.script.javascript.RhinoScriptEngineFactory的javax.script.ScriptEngineFactory文件。这完成了最基本的功能,不过这还不够。因为默认的com.sun.script.javascript.RhinoScriptEngine的实现中,把E4X禁用掉了。做法是我前面说的一样,反编译之后可以看到:
java 代码
- ContextFactory.initGlobal(new ContextFactory() {
-
- protected Context makeContext()
- {
- Context context = super.makeContext();
- context.setClassShutter(RhinoClassShutter.getInstance());
- context.setWrapFactory(RhinoWrapFactory.getInstance());
- return context;
- }
-
- public boolean hasFeature(Context context, int i)
- {
- if(i == 6)
- return false;
- else
- return super.hasFeature(context, i);
- }
-
- }
- );
从代码中可以看到,6就是E4X的feature,默认的处理是直接返回false,要把它改成返回true。由于没有源代码,所以解决办法就只有一个,直接生成Java字节码。这个很多工具可以做到,我用的是ASM,首先查看原始的RhinoScriptEngine$1.class的字节码,然后修改一处地方就可以了。用此class文件替换到原来的,就完成了第一步。
第二步是因为JDK6对Rhino做了很多修改,很多类都去掉或者进行了修改,类所在的包也变化了。因此有两种方案,一种是修改com.sun.script下面的class文件,让它加载我们提供的org.mozilla.javascript下面的类,不过这会修改多个class文件,不理想。所以我的方案是把已有的Rhino的源代码结构修改成现有的sun实现的结构,删除掉sun原来的Rhino的类,这样com.sun.script下面的类就会加载完整功能的Rhino了。要完成这样的功能,需要对Rhino的代码进行修改,把org.mozilla映射到sun.org.mozilla,org.mozilla.javasscript下面的映射到sun.org.mozilla.javascript.internal。我写了一个Python脚本来完成这个工作。编译这些文件就可以得到新的jar,放到classpath下面就可以了。
至此,就可以在JDK 6中利用JSR223来使用Rhino的E4X了。测试一下就可以了:
java 代码
- ScriptEngineManager sem = new ScriptEngineManager();
- ScriptEngine engine = sem.getEngineByName(”js”);
- if (engine != null) {
- String str = “var i = Math.cos(Math.PI);print(i);var order = <order><person>alex</person></order>;print(order.person);”;
- try {
- Object result = engine.eval(str);
- System.out.println(result);
- } catch (ScriptException e) {
- e.printStackTrace();
- }
- }
下载地址:suncrack.jar