Search code examples
javascriptjava-8nashorn

(De)referencing method variant in Java Nashorn


Consider the code:

Example 1

var Executors = java.util.concurrent.Executors;
var executor = Executors.newCachedThreadPool();
var fork = function (callable) {
    // Clarify Runnable versus Callable overloaded methods
    executor['submit(java.util.concurrent.Callable)'](callable);
};

fork(function(){ ... }); //ok

This works.

But this does not work:

Example 2

var Executors = java.util.concurrent.Executors;
var executor = Executors.newCachedThreadPool();
var fork = executor['submit(java.util.concurrent.Callable)'];

fork(function(){ ... }); //fails, NullPointerException

I assume, it is because fork here is not a JS Function instance, it is actually an instance of jdk.internal.dynalink.beans.SimpleDynamicMethod

I tried to use fork.apply(executor,function() { ... }); but natrually, SimpleDynamicMethod has no apply.

Why is it, actually, that Example 2 does not work, while Example 1 does?

Is it simply a perk of Nashorn? It there a better way to define fork() function than in Example 1?

Update

In example 2,

print(typeof fork); reports function

print(fork) reports [jdk.internal.dynalink.beans.SimpleDynamicMethod Future java.util.concurrent.AbstractExecutorService.submit(Callable)]

and exception is (with line 13 reading fork(function() {)

Exception in thread "main" java.lang.NullPointerException
    at jdk.nashorn.internal.scripts.Script$\^eval\_._L5(<eval>:13)
    at jdk.nashorn.internal.scripts.Script$\^eval\_.runScript(<eval>:5)
    at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:527)

Solution

  • The problem is that you are missing the receiver 'executor' from the call. In general, 'fetching' Java functions is only practical with static Java functions. For example:

    jjs> var abs = java.lang.Math.abs;
    jjs> abs(-10);
    10
    

    In your example, we could have bound fork to executor and make it equivalently static. This support is currently not present. We should probably have support for adding the receiver as the first argument if 'fetched' from a class. Will file an enhancement request for a future release.