Discussion:
Bug report: can't call static methods on a Java class instance
Tal Liron
2013-10-09 14:13:24 UTC
Permalink
If we have a Java class:

class MyClass {
public static void myMethod();
}

And in JavaScript try:

myInstance.myMethod()

Then we would get an exception that looks something like this:

myscript.js:... TypeError: ***@... has no such function "myMethod"
at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:56)
at
jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:212)
at
jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:184)
at
jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:171)
at
jdk.nashorn.internal.runtime.linker.NashornBottomLinker.linkBean(NashornBottomLinker.java:113)
at
jdk.nashorn.internal.runtime.linker.NashornBottomLinker.getGuardedInvocation(NashornBottomLinker.java:68)
at
jdk.internal.dynalink.support.CompositeGuardingDynamicLinker.getGuardedInvocation(CompositeGuardingDynamicLinker.java:124)
at
jdk.internal.dynalink.support.LinkerServicesImpl.getGuardedInvocation(LinkerServicesImpl.java:138)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:232)
at
jdk.nashorn.internal.scripts.Script$default.runScript(component/services/sincerity/version/default.js:6)
at
jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:527)
at
jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:204)
at
jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:367)
Attila Szegedi
2013-10-09 14:55:10 UTC
Permalink
Yup. Static methods can't be invoked on instances. This is by design. The following will work:

Java.type("MyClass").myMethod()

of course, you can reuse it as:

var MyClass = Java.type("MyClass")
...
MyClass.myMethod()

As a matter of fact, you can even get the method and invoke it later:

var myMethod = Java.type("MyClass").myMethod
...
myMethod()

This will also work:

myInstance.class.static.myMethod()

as "static" is a synthetic property on java.lang.Class objects that returns the object representing their static facet (basically, containing static members and acting as a constructor - the same object Java.type() returns).

Attila.
Post by Tal Liron
class MyClass {
public static void myMethod();
}
myInstance.myMethod()
at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:56)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:212)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:184)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:171)
at jdk.nashorn.internal.runtime.linker.NashornBottomLinker.linkBean(NashornBottomLinker.java:113)
at jdk.nashorn.internal.runtime.linker.NashornBottomLinker.getGuardedInvocation(NashornBottomLinker.java:68)
at jdk.internal.dynalink.support.CompositeGuardingDynamicLinker.getGuardedInvocation(CompositeGuardingDynamicLinker.java:124)
at jdk.internal.dynalink.support.LinkerServicesImpl.getGuardedInvocation(LinkerServicesImpl.java:138)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:232)
at jdk.nashorn.internal.scripts.Script$default.runScript(component/services/sincerity/version/default.js:6)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:527)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:204)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:367)
Tal Liron
2013-10-09 14:58:14 UTC
Permalink
I understand the workaround, but again I fail to see the rationale
behind Nashorn's overly-strict interface to Java. What's wrong with
supporting the shorthand in Nashorn, especially when Rhino behaves as
JavaScript programmers would expect?
Post by Attila Szegedi
Java.type("MyClass").myMethod()
var MyClass = Java.type("MyClass")
...
MyClass.myMethod()
var myMethod = Java.type("MyClass").myMethod
...
myMethod()
myInstance.class.static.myMethod()
as "static" is a synthetic property on java.lang.Class objects that returns the object representing their static facet (basically, containing static members and acting as a constructor - the same object Java.type() returns).
Attila.
Post by Tal Liron
class MyClass {
public static void myMethod();
}
myInstance.myMethod()
at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:56)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:212)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:184)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:171)
at jdk.nashorn.internal.runtime.linker.NashornBottomLinker.linkBean(NashornBottomLinker.java:113)
at jdk.nashorn.internal.runtime.linker.NashornBottomLinker.getGuardedInvocation(NashornBottomLinker.java:68)
at jdk.internal.dynalink.support.CompositeGuardingDynamicLinker.getGuardedInvocation(CompositeGuardingDynamicLinker.java:124)
at jdk.internal.dynalink.support.LinkerServicesImpl.getGuardedInvocation(LinkerServicesImpl.java:138)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:232)
at jdk.nashorn.internal.scripts.Script$default.runScript(component/services/sincerity/version/default.js:6)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:527)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:204)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:367)
Attila Szegedi
2013-10-09 15:25:26 UTC
Permalink
I understand the workaround, but again I fail to see the rationale behind Nashorn's overly-strict interface to Java. What's wrong with supporting the shorthand in Nashorn, especially when Rhino behaves as JavaScript programmers would expect?
I'm not sure what expectation a JavaScript programmer could intrinsically have with regard to the functionality of the Java platform. (E.g. a concept of instance vs. static members not sharing a namespace on an object). Java platform and JavaScript are independent, so a theoretical "JavaScript programmer" should have no a priori expectations with regard to how platform integration features work. A "JavaScript programmer used to work with Rhino" is a different kind of creature, of course.

Implementing functionality on the border of a language and its host platform will always be a tradeoff between leaning more towards one side or more towards the other. Where decisions need to be made, they will always reflect the convictions of its designers. My conviction is that exposing static members through instances is a sloppy mashing together of otherwise separate namespaces, hence I chose not to enable it. (Using instances to invoke static methods is also a discouraged practice in Java, where it additionally carries an unnecessary null dereference risk). I actually frowned upon Rhino supporting that.

I believe that where I had to make design decisions, I made them in the direction of helping people write more maintainable and clear code in the long run, even if it means not having some, as you'd say "convenient shortcuts". At the end of the day, Nashorn isn't Rhino. It's quite similar in lots of regards, but when needed, we deliberated and went with different choices when we felt we need to. It's a different runtime. (Notwithstanding, I think we'll do something about the array conversions…)

Attila.
Post by Attila Szegedi
Java.type("MyClass").myMethod()
var MyClass = Java.type("MyClass")
...
MyClass.myMethod()
var myMethod = Java.type("MyClass").myMethod
...
myMethod()
myInstance.class.static.myMethod()
as "static" is a synthetic property on java.lang.Class objects that returns the object representing their static facet (basically, containing static members and acting as a constructor - the same object Java.type() returns).
Attila.
Post by Tal Liron
class MyClass {
public static void myMethod();
}
myInstance.myMethod()
at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:56)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:212)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:184)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:171)
at jdk.nashorn.internal.runtime.linker.NashornBottomLinker.linkBean(NashornBottomLinker.java:113)
at jdk.nashorn.internal.runtime.linker.NashornBottomLinker.getGuardedInvocation(NashornBottomLinker.java:68)
at jdk.internal.dynalink.support.CompositeGuardingDynamicLinker.getGuardedInvocation(CompositeGuardingDynamicLinker.java:124)
at jdk.internal.dynalink.support.LinkerServicesImpl.getGuardedInvocation(LinkerServicesImpl.java:138)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:232)
at jdk.nashorn.internal.scripts.Script$default.runScript(component/services/sincerity/version/default.js:6)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:527)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:204)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:367)
Tal Liron
2013-10-09 15:42:29 UTC
Permalink
Again, I do understand your conviction, but "sloppy" (or "simple"?) is
exactly what most dynamic languages are all about. If a programmer
wanted to use Java, they would. But when working in JavaScript,
expectations are quite different. Unfortunately, in my opinion, Nashorn
right now requires JavaScript programmers to understand Java paradigms
when using Java classes, objects and even method calls. Almost all other
JVM dynamic languages treat Java classes and objects as natively as
possible, some more opaquely than others (JRuby does a truly marvelous
job at allowing you duck-type Java instances).

I also think you're thinking more of clean-room JavaScript programs in
your design. But actually Nashorn will be used more widely, I think, in
specialized embedded environments which set up bindings for
domain-specific APIs, and invariably these APIs will be written in Java.
Nashorn unfortunately will not "just work" with these Java-made APIs,
but would require an additional layer of JavaScript wrappers to do the
coercsions and other "shortcuts" that Nashorn is not doing for us. Using
Nashorn's special Java.* APIs would be clumsy if not unacceptable in
such environments, even if well-documented.

Would it not be possible to allow for your generally reasonable
conviction via something like a "strict_java" flag? When this flag is
off, Nashorn could work in a "sloppy" mode.

I'm 100% sure you'll be getting these kinds of confused questions again
and again from JavaScript programmers.
Post by Attila Szegedi
I understand the workaround, but again I fail to see the rationale behind Nashorn's overly-strict interface to Java. What's wrong with supporting the shorthand in Nashorn, especially when Rhino behaves as JavaScript programmers would expect?
I'm not sure what expectation a JavaScript programmer could intrinsically have with regard to the functionality of the Java platform. (E.g. a concept of instance vs. static members not sharing a namespace on an object). Java platform and JavaScript are independent, so a theoretical "JavaScript programmer" should have no a priori expectations with regard to how platform integration features work. A "JavaScript programmer used to work with Rhino" is a different kind of creature, of course.
Implementing functionality on the border of a language and its host platform will always be a tradeoff between leaning more towards one side or more towards the other. Where decisions need to be made, they will always reflect the convictions of its designers. My conviction is that exposing static members through instances is a sloppy mashing together of otherwise separate namespaces, hence I chose not to enable it. (Using instances to invoke static methods is also a discouraged practice in Java, where it additionally carries an unnecessary null dereference risk). I actually frowned upon Rhino supporting that.
I believe that where I had to make design decisions, I made them in the direction of helping people write more maintainable and clear code in the long run, even if it means not having some, as you'd say "convenient shortcuts". At the end of the day, Nashorn isn't Rhino. It's quite similar in lots of regards, but when needed, we deliberated and went with different choices when we felt we need to. It's a different runtime. (Notwithstanding, I think we'll do something about the array conversions…)
Attila.
Post by Attila Szegedi
Java.type("MyClass").myMethod()
var MyClass = Java.type("MyClass")
...
MyClass.myMethod()
var myMethod = Java.type("MyClass").myMethod
...
myMethod()
myInstance.class.static.myMethod()
as "static" is a synthetic property on java.lang.Class objects that returns the object representing their static facet (basically, containing static members and acting as a constructor - the same object Java.type() returns).
Attila.
Post by Tal Liron
class MyClass {
public static void myMethod();
}
myInstance.myMethod()
at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:56)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:212)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:184)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:171)
at jdk.nashorn.internal.runtime.linker.NashornBottomLinker.linkBean(NashornBottomLinker.java:113)
at jdk.nashorn.internal.runtime.linker.NashornBottomLinker.getGuardedInvocation(NashornBottomLinker.java:68)
at jdk.internal.dynalink.support.CompositeGuardingDynamicLinker.getGuardedInvocation(CompositeGuardingDynamicLinker.java:124)
at jdk.internal.dynalink.support.LinkerServicesImpl.getGuardedInvocation(LinkerServicesImpl.java:138)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:232)
at jdk.nashorn.internal.scripts.Script$default.runScript(component/services/sincerity/version/default.js:6)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:527)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:204)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:367)
Loading...