Invocable.getInterface fails across classloaders in web app

Attila Szegedi attila.szegedi at oracle.com
Tue Jul 28 16:12:43 UTC 2015


Create an instance of jdk.nashorn.api.scripting.NashornScriptEngineFactory directly instead of doing engineManager.engineByName(), then create a ScriptEngine by invoking NashornScriptEngineFactory.getScriptEngine(ClassLoader appLoader) and passing it your app-level loader.

Hope that helps,
  Attila.

(I’ll answer to StackOverflow too.)

> On Jul 28, 2015, at 6:04 PM, Максим Гумеров <mgumerov at gmail.com> wrote:
> 
> Hello!
> Recently I posted a question at stackoverflow, so far no one had the
> answer, so I thought I might find one here.
> 
> My original question is here:
> http://stackoverflow.com/questions/31669566/nashorn-javascript-invocable-getinterface-fails-across-classloaders-in-web-app
> 
> For reader's comfort, I will reproduce its below.
> Thank you!
> Maksim
> 
> ====
> 
> I need to invoke (with Nashorn) from Java code a function defined in
> JavaScript and to pass there some parameters. Instead of using
> Invocable.invokeFunction("Foo", arg1, arg2), I was going to define an
> interface, then request Invocable to produce its implementation, just like
> Oracle suggests here
> <http://www.oracle.com/technetwork/articles/java/jf14-nashorn-2126515.html%20%22here'>,
> "Embedding Oracle Nashorn":
> 
> package mypackage;public final class MyClass {
>  public interface Composer {
>    void compose(final StringBuilder subject, final StringBuilder body);
>  }
> 
>  public void composeEmail(...) {
>      ...
>      final ScriptEngineManager engineManager = new ScriptEngineManager();
>      final ScriptEngine engine = engineManager.getEngineByName("nashorn");
>      engine.eval(scriptText);
>      final Invocable invocable = (Invocable) engine;
>      final Composer composer = (Composer)invocable.getInterface(Composer);
>      composer.compose(subject, body);
>      ...
>  }}
> 
> Problem is, since I am doing this in a web application running in Tomcat,
> my Composer gets loaded by app-level classloader, while nashorn classes
> were loaded by extensions class loader. So getInterface fails saying a
> *TypeError:
> Can not find a common class loader for ScriptObject and mypackage.Composer*
> 
> Any ideas how to overcome that? I could, of course, try to load Composer in
> a parent classloader, in an assumption (hack-like) that it is actually an
> ext loader, but there is at least one problem with that: it cannot find my
> class. I suppose it's quite right: my package resides in my web
> application, and extension loader does not look there. Any other great
> ideas?
> 
> P.S. And now I noticed that this message is weird: if an app classloader
> delegates to ext classloader, then of course the latter is the common
> classloader for them. Maybe they were trying to say that the target
> interfaces's classloader must be equal to actual implementation's
> classloader, or the implementation's classloader must delegate to the
> target's (but not vice versa)?



More information about the nashorn-dev mailing list