Java 7和Rhino 1.7R3是否支持CommonJS模块?

7

我需要帮助让Java 7和Rhino 1.7R3支持CommonJS。

Rhino 1.7R3支持CommonJS模块:

Java 7自带Rhino 1.7R3。不幸的是,Java 7的Rhino是一个修改过的版本,它不包含org.mozilla.javascript.commonjs包:

我想使用Rhino 1.7R3通过javax.script API支持CommonJS,具体操作如下:

ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
engine.put("markdown", markdown);
engine.eval("var html = require('./Markdown.Sanitizer').getSanitizingConverter().makeHtml(markdown);");
return (String) engine.get("html");

我通过ScriptEngineManager验证了我确实使用的是Rhino 1.7R3引擎。我认为,也许我只需要将以下依赖项添加到类路径中。

<dependency>
    <groupId>org.mozilla</groupId>
    <artifactId>rhino</artifactId>
    <version>1.7R3</version>
</dependency>

同时,CommonJS——特别是require()——应该开始工作了。但它没有。当我尝试使用require()时,出现了问题。

Caused by: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "require" is not defined. (<Unknown source>#2)
    at sun.org.mozilla.javascript.internal.ScriptRuntime.constructError(ScriptRuntime.java:3773)
    at sun.org.mozilla.javascript.internal.ScriptRuntime.constructError(ScriptRuntime.java:3751)
    at sun.org.mozilla.javascript.internal.ScriptRuntime.notFoundError(ScriptRuntime.java:3836)

我该如何让Java 7与Rhino 1.7R3完整版配合使用,以便获得CommonJS支持?
编辑:我找到了以下问题,它涉及完全相同的主题: 疯狂检查:Rhino没有require函数,对吗? 回答者建议也许可以用CommonJS Rhino 1.7R3替换有限的Rhino 1.7R3,但没有说明如何做到这一点。这就是我在这里提问的原因。
3个回答

11

编辑:看起来你不需要使用JVM引导类加载器。Sun已经将默认的Rhino实现类放入了

sun.org.mozilla.javascript.*

包。但是您加载的Rhino实现将占用

org.mozilla.javascript.*

因此它们不应该发生冲突。然而,如果出现问题,您可以通过引导类加载器覆盖JDK中的类。您有两个选项:基本上,您需要覆盖类路径,以便您的Rhino类优先于内置类。
  1. Simply put the rhino-1.7R3.jar to your-JRE-path\lib\ext. This way Rhino jar will be added to Java Bootsrap classloader and will be loaded before the build-in JavaScript jar.
  2. Alternatively, if you don't have an access to ../lib/ext you can use a command-line option:

    -Xbootclasspath/a:path/to/rhino-1.7R3.jar
    

犀牛本身并没有实现Java Scripting API。为了将犀牛集成到JDK中,Sun公司实现了自己的ScriptEngineScriptEngineFactory。因此,如果您加载自己的rhino-1.7R3.jar,则无法在加载脚本时使用Common JS。

ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");

相反,您有两个选择。

  1. Implement your own ScriptEngine, ScriptEngineFactoryand other related classes on top of Rhino API. See how Oracle does it. Note however, that JDK sources are under GPL 2 license so you should either release your custom Script Engine wrapper for Rhino or only use those classes as a reference and don't copy the code.

  2. Use Rhino API directly. I highly recommend this approach. There are docs and examples on Mozilla website but the basic API is relatively simple:

    // Execution environment for Rhino
    // there should be only one context in a giver thread
    Context cx = Context.enter();
    // Object.prototype, Function prototype, etc.
    Scriptable scope = cx.initStandardObjects();
    
    // Execute script from a given java.io.Reader
    Object result = cx.evaluateReader(scope, reader, 0, null);
    // If returning result isn't sufficient for your needs
    // you can do something like this:
    Object someVar = scope.get("someVar");
    
    // Don't forget to close the context when you're done
    Context.exit();
    

或者,我可以给你提供几个纯JS的解决方案。

  1. 看看Browserify。它是一个JavaScript预处理器,可以将您的源代码组合成单个包。
  2. 重写您的模块,以便使用AMDUMD,然后使用r.js工具将它们组合起来。

这两个选项都需要您在构建过程中添加JS预处理步骤,并可能会使调试代码有点困难。


3
这个问题很老了,但对于那些从谷歌来到这里的人,你可以使用以下方式在Rhino中设置CommonJS支持(下面只是一种方法):
(我只是直接调用Rhino,而不使用Java的脚本API)
List<URI> paths = Arrays.asList(new URI[] { new File("js/require/paths/here").toURI() });
Context ctx = Context.enter();
Scriptable scope = ctx.initStandardObjects();

new RequireBuilder()
    .setModuleScriptProvider(new SoftCachingModuleScriptProvider(
        new UrlModuleSourceProvider(paths, null)))
    .setSandboxed(true)
    .createRequire(ctx, scope)
    .install(scope);

//
// now you can ctx.evaluateString(...) and use require()
//

Context.exit();

Now you may have two files:

main.js

require('require-test.js')()

require-test.js

module.exports = function() {
    java.lang.System.out.println('The CommonJS require function works!')
}

0
如果您使用的是Gradle构建系统。 我通过在项目gradle文件中添加此依赖项成功解决了此问题。 (基于这里compile group:'org.mozilla',name:'rhino',version:'1.7.10' 并且您必须将导入的包名称从sun.org.mozilla.javascript.internal替换为org.mozilla.javascript在您的java类文件中。
// import sun.org.mozilla.javascript.internal.NativeObject; // <=== Do not use this package.
import org.mozilla.javascript.NativeObject;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

一切都运行正常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接