7

我需要帮助 CommonJS 在 Java 7 和 Rhino 1.7R3 上工作。

Rhino 1.7R3 支持 CommonJS 模块:

Java 7 与 Rhino 1.7R3 捆绑在一起。不幸的是,Java 7 的 Rhino 是一个修改版本,它不包含该org.mozilla.javascript.commonjs包:

我想通过javax.scriptAPI 使用 Rhino 1.7R3 对 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,但没有说明如何做到这一点。这就是我在这里要问的。

4

3 回答 3

11

编辑:似乎你根本不需要使用 JVM 引导类加载器。Sun 已将默认的 Rhino 实现类放入

sun.org.mozilla.javascript.*

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

org.mozilla.javascript.*

因此它们不应该发生碰撞。但是,如果出现问题,您可以在引导类加载器的帮助下覆盖 JDK 中的类。你有两个选择:

基本上你需要覆盖类路径,以便你的 Rhino 类优先而不是内置类。

  1. 只需将 rhino-1.7R3.jar 放入 your-JRE-path\lib\ext 即可。这样,Rhino jar 将被添加到 Java Bootsrap 类加载器中,并将在内置 JavaScript jar 之前加载。
  2. 或者,如果您无权访问 ../lib/ext,您可以使用命令行选项:

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

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

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

相反,您有两个选择。

  1. 在 Rhino API 之上实现您自己的ScriptEngine和其他相关的类。 看看Oracle 是如何做到的。但是请注意,JDK 源代码在 GPL 2 许可下,因此您应该为 Rhino 发布您的自定义脚本引擎包装器,或者仅使用这些类作为参考并且不要复制代码。ScriptEngineFactory

  2. 直接使用 Rhino API我强烈推荐这种方法。 Mozilla 网站上有文档和示例,但基本 API 相对简单:

    // 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 预处理步骤,这可能会使调试代码有点困难。

于 2012-06-18T10:02:09.197 回答
2

这个问题很老,但对于那些来自谷歌的人来说,你可以使用以下方法在 Rhino 中设置 CommonJS 支持(以下只是一种方法):

(我只是直接调用 Rhino,而不是使用 Java 的 Scripting 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();

现在你可能有两个文件:

main.js

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

需要-test.js

module.exports = function() {
    java.lang.System.out.println('The CommonJS require function works!')
}
于 2015-05-20T16:28:07.693 回答
0

如果您使用Gradle构建系统。我通过在项目 gradle 文件中添加此依赖项成功解决了此问题。(基于这里

compile group: 'org.mozilla', name: 'rhino', version: '1.7.10'

并且您必须在您的 java 类文件中将导入的包名称替换为sun.org.mozilla.javascript.internalto 。org.mozilla.javascript

// 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;

一切正常。

于 2018-11-28T05:37:29.913 回答