Alex Pakka
Alex Pakka

Reputation: 9706

(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)

Upvotes: 3

Views: 1398

Answers (3)

Attila Szegedi
Attila Szegedi

Reputation: 4595

Unfortunately, currently you can't use bind, apply, and call with POJO methods. I'd like to add that as a future enhancement. The best you can currently do in your above example is:

executor['submit(Callable)'](function() { ... })

Note that while in general indexed access to a property (using the [] operator) is less efficient than property name access (using the . operator), Nashorn recognizes indexed access with a string literal and treats it just as efficiently as a property name access, so you don't suffer a slowdown here, just a bit of visual noise. In the case above, it will actually end up getting linked to the executor's virtual method directly.

Speaking of visual noise, you don't have to fully qualify java.util.concurrent.Callable. When the non-qualified name of the parameter type is sufficient to disambiguate the overloads (which is pretty much always), you can just use the non-qualified name, regardless of what package it is in (works for your own classes too).

Upvotes: 3

wickund
wickund

Reputation: 1177

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.

Upvotes: 1

Vik Gamov
Vik Gamov

Reputation: 5456

Alex,

In example 1, var fork is a function that returns array executor. In example 2, var fork is an array. That is why you cant use () and apply.

Does fork[0](function(){...}) work for you ?

Thanks

Upvotes: 0

Related Questions