How can I determine which javascript engine, rhino or nashorn is running my code? - Stack Overflow

There are several questions how to determine the javascript engine in browser.I have to write javascri

There are several questions how to determine the javascript engine in browser. I have to write javascript code that has to run on rhino and nashorn.

How can I determine if my code is running on rhino or nashorn? Are there typcial functions, variables, constants where you can determine the engine?

There are several questions how to determine the javascript engine in browser. I have to write javascript code that has to run on rhino and nashorn.

How can I determine if my code is running on rhino or nashorn? Are there typcial functions, variables, constants where you can determine the engine?

Share Improve this question edited Jun 9, 2016 at 8:07 hippietrail 17.1k21 gold badges109 silver badges179 bronze badges asked Jun 9, 2016 at 6:46 Christian13467Christian13467 5,6341 gold badge32 silver badges34 bronze badges 4
  • 3 Interesting. Why do you need the check? – T.J. Crowder Commented Jun 9, 2016 at 6:49
  • If you're asking about rhino vs nashorn, aren't you just asking about JDK SE 8 vs >8? – John Green Commented Jun 9, 2016 at 6:57
  • @JohnGreen: "...about JDK SE 8 vs >8?" Nashorn was added in JDK8 (not >8). And it's still possible to run Rhino in JDK8 (but you have to add a jar and do it on purpose). – T.J. Crowder Commented Jun 9, 2016 at 7:05
  • 1 We allow customers to setup there favorite engine. I just want to be shure what is set up, when no one can tell me, what they have done. – Christian13467 Commented Jun 9, 2016 at 8:25
Add a ment  | 

3 Answers 3

Reset to default 1

Looking at the Rhino to Nashorn migration guide, I see several possible ways.

If you're not using the Rhino patibility script, this would do it:

var usingNashorn = typeof importClass !== "function";

...since importClass is defined for Rhino but not for Nashorn (unless you include the patibility script).

I think Java.type is Nashorn-specific, so:

var usingNashorn = typeof Java !== "undefined" && Java && typeof Java.type === "function";

You could check for wrapping of exceptions:

var usingNashorn;
try {
    // Anything that will throw an NPE from the Java layer
    java.lang.System.loadLibrary(null);
} catch (e) {
    // false!
    usingNashorn = e instanceof java.lang.NullPointerException;
}

...since the migration guide says that will be true for Nashorn but false for Rhino. It does involve throwing an exception, which is unfortunate.

With --no-java option, "Java" is not defined as object in Nashorn. Best would be to check something that is available always in Nashorn. Something like DIR or FILE variable is a good candidate. Always there in nashorn.

jjs> typeof DIR

string

If you are using javax.script API (and not jjs), you can get the engine name and check as well:

import javax.script.*;

public class Main {
   public static void main(String[] args) throws Exception {
     ScriptEngineManager m = new ScriptEngineManager();
     ScriptEngine e = m.getEngineByName("nashorn");
     System.out.println(e.getFactory().getEngineName());
   }
}

With Nashorn, you'd see "Oracle Nashorn" as the engine name.

I think the most robust and straightforward way to do this is to rely on the fact that both Rhino and Nashorn create per-thread execution contexts to do their work.

Nashorn's can be a bit more plicated to access because of the module (JPMS) changes introduced in Java 9, which makes it more difficult for scripts to access some of the classes involved.

Here's some code I use for this, in the SLIME codebase (which similarly supports both engines, and JDK 8/11 as of this writing). In each case, the engine provides a running method that returns the engine-specific context if we are running inside that engine (so for simple detection, it could be wrapped inside a call to Boolean or whatever). It is tested but as it's copy-paste out of context, it contains a bit of extraneous information, apologies for that:

Rhino (in this implementation you must call isPresent() and ensure it returns true before calling running(), although you could improve that):

        var rhino = (
            function(global) {
                return {
                    isPresent: function() {
                        return typeof(global.Packages.mozilla.javascript.Context.getCurrentContext) == "function";
                    },
                    running: function() {
                        return global.Packages.mozilla.javascript.Context.getCurrentContext();
                    }
                }
            }
        )(this);

Nashorn (relies on Packages, provided by the Mozilla patibility layer, mostly to improve static type-checking, but could easily be rewritten to use the Java equivalents for Nashorn):

        var nashorn = (
            function() {
                //  TODO    A little bit of this logic is duplicated in loader/jrunscript/nashorn.js; we could make this method
                //          available there somehow, perhaps, although it might be tricky getting things organized between
                //          bootstrapping Nashorn in the loader and loading the launcher bootstrap script
                var Context = Packages.jdk.nashorn.internal.runtime.Context;
                var $getContext;
                if (typeof(Context) == "function") {
                    try {
                        //  TODO    is there any way to avoid repeating the class name?
                        $getContext = Packages.java.lang.Class.forName("jdk.nashorn.internal.runtime.Context").getMethod("getContext");
                    } catch (e) {
                        //  do nothing; $getContext will remain undefined
                    }
                }

                var isPresent = function() {
                    if (!new Packages.javax.script.ScriptEngineManager().getEngineByName("nashorn")) {
                        $api.debug("Nashorn not detected via javax.script; removing.");
                        return false;
                    }
                    if (typeof(Context.getContext) != "function" && !$getContext) {
                        $api.debug("jdk.nashorn.internal.runtime.Context.getContext not accessible; removing Nashorn.")
                        return false;
                    }
                    return true;
                }

                return {
                    isPresent: isPresent,
                    running: function() {
                        if ($getContext) {
                            try {
                                return $getContext.invoke(null);
                            } catch (e) {
                                return null;
                            }
                        } else {
                            return null;
                        }
                    }
                }
            }
        )();

Sure, the Nashorn implementation uses non-public APIs. But I still think this is better, and more straightforward, than relying on what are essentially side effects (existence of various cherry-picked APIs that one or the other engine might provide). These techniques are potentially breakable if either engine seeks to improve patibility with the other.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745229608a4617618.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信