简体   繁体   English

Java 7 + Rhino 1.7R3支持CommonJS模块?

[英]Java 7 + Rhino 1.7R3 support for CommonJS modules?

I need help getting CommonJS working on Java 7 and Rhino 1.7R3. 我需要帮助让CommonJS使用Java 7和Rhino 1.7R3。

Rhino 1.7R3 supports CommonJS modules: Rhino 1.7R3支持CommonJS模块:

And Java 7 comes bundled with Rhino 1.7R3. Java 7与Rhino 1.7R3捆绑在一起。 Unfortunately, Java 7's Rhino is a modified version, and it does not include the org.mozilla.javascript.commonjs package: 不幸的是,Java 7的Rhino是一个修改版本,它不包括org.mozilla.javascript.commonjs包:

I would like to use Rhino 1.7R3's support for CommonJS through the javax.script API as follows: 我想通过javax.script API使用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");

(I verified through the ScriptEngineManager that I am indeed using the Rhino 1.7R3 engine.) I thought that perhaps I could just add the following dependency to the classpath (我通过ScriptEngineManager验证我确实使用的是Rhino 1.7R3引擎。)我想也许我可以将以下依赖项添加到类路径中

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

and CommonJS—specifically, require() —would start working. 和CommonJS一样, require() - 将开始工作。 But it doesn't. 但事实并非如此。 When I try to use require() I get 当我尝试使用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)

How do I get Java 7 to work with the full version of Rhino 1.7R3 so I can get CommonJS support? 如何让Java 7与完整版Rhino 1.7R3一起使用,以便获得CommonJS支持?

EDIT: I found the following question, which deals with exactly the same topic: 编辑:我发现了以下问题,它涉及完全相同的主题:

Sanity check: Rhino does not have a require function, right? 完整性检查:Rhino没有require函数,对吧?

The respondent suggests that maybe it's possible to replace the limited Rhino 1.7R3 with the CommonJS Rhino 1.7R3, but doesn't say how one might do that. 受访者表示也许可以用CommonJS Rhino 1.7R3替换有限的Rhino 1.7R3,但没有说明如何做到这一点。 That's what I'm asking about here. 这就是我在这里问的问题。

Edit : Seems like you don't need to use JVM bootstrap classloader after all. 编辑 :看起来你毕竟不需要使用JVM引导程序类加载器。 Sun has put the default Rhino implementation classes into Sun已将默认的Rhino实现类放入其中

sun.org.mozilla.javascript.*

package. 包。 But your loaded Rhino implementation will occupy 但是你加载的Rhino实现将会占用

org.mozilla.javascript.*

Thus they shouldn't collide. 因此他们不应该碰撞。 However if something goes wrong you can override classes in JDK with the help of bootstrap classloader. 但是, 如果出现问题,您可以在bootstrap类加载器的帮助下覆盖JDK中的类。 You have two options: 您有两种选择:

Basically you need to override the classpath so that your Rhino classes would take preference instead of the build-in ones. 基本上你需要覆盖类路径,以便你的Rhino类优先于内置而不是内置类。

  1. Simply put the rhino-1.7R3.jar to your-JRE-path\\lib\\ext. 只需将rhino-1.7R3.jar放到-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. 这样,Rhino jar将被添加到Java Bootsrap类加载器中,并将在内置JavaScript jar之前加载。
  2. Alternatively, if you don't have an access to ../lib/ext you can use a command-line option: 或者,如果您无法访问../lib/ext,则可以使用命令行选项:

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

The Rhino itself does not implement Java Scripting API. Rhino本身实现Java Scripting API。 In order to integrate Rhino into JDK Sun had implemented their own ScriptEngine and ScriptEngineFactory . 为了将Rhino集成到JDK中,Sun已经实现了自己的ScriptEngineScriptEngineFactory Thus, if you load your own rhino-1.7R3.jar you won't be able to use Common JS if you load your scripts with 因此,如果您加载自己的rhino-1.7R3.jar ,如果加载脚本,则无法使用Common JS

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

Instead you have two options. 相反,你有两个选择。

  1. Implement your own ScriptEngine , ScriptEngineFactory and other related classes on top of Rhino API. 在Rhino API之上 实现您自己的 ScriptEngineScriptEngineFactory 和其他相关类。 See how Oracle does it . 了解Oracle如何做到这一点 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. 但请注意,JDK源代码属于GPL 2许可证,因此您应该为Rhino发布自定义脚本引擎包装器,或者仅将这些类用作参考,不要复制代码。

  2. Use Rhino API directly . 直接使用Rhino API I highly recommend this approach. 我强烈推荐这种方法。 There are docs and examples on Mozilla website but the basic API is relatively simple: 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(); 

Alternatively, I can give you a number of JS-only solutions. 或者,我可以为您提供一些仅限JS的解决方案。

  1. Take a look at Browserify . 看看Browserify It's a JavaScript preprocessor which will combine your source code into a single bundle. 它是一个JavaScript预处理器,它将您的源代码组合到一个包中。
  2. Rewrite your modules so that they use either AMD or UMD and then combine them with r.js tool . 重写您的模块,以便他们使用AMDUMD ,然后将它们与r.js工具结合使用。

Both options require you to add a js preprocessing step to your build process and may make debugging your code a bit difficult. 这两个选项都要求您在构建过程中添加一个js预处理步骤,并且可能会使调试代码变得有点困难。

This question is old, but for those coming here from Google, you can setup CommonJS support in Rhino with the following (below is just one way): 这个问题已经过时了,但对于那些来自谷歌的人来说,您可以使用以下方法在Rhino中设置CommonJS支持(以下只是一种方式):

(I am just calling Rhino directly, not using Java's Scripting API) (我只是直接调用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();

Now you may have two files: 现在您可能有两个文件:

main.js main.js

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

require-test.js 要求-test.js

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

If you use Gradle build system. 如果您使用Gradle构建系统。 I successfully fixed this issue via adding this dependency in the project gradle file. 我通过在项目gradle文件中添加此依赖项成功修复了此问题。 (based on here ) (基于这里

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

And you have to replace imported package name from sun.org.mozilla.javascript.internal to org.mozilla.javascript in your java class file. 并且您必须将导入的包名称从sun.org.mozilla.javascript.internal为java类文件中的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;

And everything works fine. 一切正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM