Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to have Nashorn load scripts from classpath?

Is it possible to have Nashorn's load method use the project's classpath when resolving URIs?

Here's what I'm attempting to do:

(defn create-engine
  "Creates a new nashorn script engine and loads dependencies into its context."
  [dependencies]
  (let [nashorn (.getEngineByName (ScriptEngineManager.) "nashorn")
        scripts (map #(str "load('" % "');") dependencies)]
    (.eval nashorn "var global = this;")
    (doseq [script scripts] (.eval nashorn script))
    nashorn))

(def app "public/javascripts/app.js") ; in /resouces, on classpath


; resulting exception:
clojure.lang.Compiler$CompilerException: 
javax.script.ScriptException: TypeError: 
Cannot load script from public/javascripts/app.js in <eval> at line number 1
like image 323
pdoherty926 Avatar asked Jan 29 '15 17:01

pdoherty926


People also ask

Is Nashorn deprecated?

The Nashorn engine has been deprecated in JDK 11 as part of JEP 335 and and has been removed from JDK15 as part of JEP 372. GraalVM can step in as a replacement for JavaScript code previously executed on the Nashorn engine.

Which JavaScript is replaced with Nashorn?

Technical Article. Until Java SE 7, JDKs shipped with a JavaScript scripting engine based on Mozilla Rhino. Java SE 8 will instead ship with a new engine called Oracle Nashorn, which is based on JSR 292 and invokedynamic .


2 Answers

Nashorn's load() method actually supports taking a URL prefixed with classpath:. It will load the file following that prefix from the classpath. Check out the source - http://cr.openjdk.java.net/~sundar/8025629/webrev.01/src/jdk/nashorn/internal/runtime/Context.java.html line 502.

like image 54
triggerpuss Avatar answered Sep 21 '22 01:09

triggerpuss


Absolute path should always start with a slash, "/public/javascripts/app.js", but I'm not sure if load() loads off the classpath, if it doesn't you may have to use eval(Reader) method and construct the reader yourself

EDIT:

You need to use the opening slash for classpath resources if the path is absolute within the jar. No slash means relative to the particular class you're calling this from. You should get an InputStream for the resource and eval a reader, in Java it would look like this:

nashorn.eval (new InputStreamReader (getClass().getResourceAsStream("/public/javascripts/app.js")));

I don't want to translate this to clojure since that's bound to end in failure.

EDIT2:

Well then here's an attempt then:

(defn create-engine
  "Creates a new nashorn script engine and loads dependencies into its context."
  [dependencies]
  (let [nashorn (.getEngineByName (ScriptEngineManager.) "nashorn")]
    (.eval nashorn "var global = this;")
    (doseq [dependency dependencies] (.eval nashorn (new InputStreamReader (.getResourceAsStream String dependency))))
    nashorn))

I shall not be held responsible if this starts the nuclear war or something

like image 42
Lev Kuznetsov Avatar answered Sep 20 '22 01:09

Lev Kuznetsov