Problem with interoperability with JavaFX WebEngine (original) (raw)

David P. Caldwell david at code.davidpcaldwell.com
Fri Mar 27 16:51:17 UTC 2015


Thanks for the pointer to the linker code, which I skimmed, and to some ideas for a workaround. I'll do some exploring. My guess is that with some kind of meta-object programming (if I used a Nashorn class) I could wrap the browser object inside something that encapsulated the logic that Sundar mentioned. Perhaps it's the Nashorn JSObject to which you allude, or perhaps some other object, but presumably I can wrap the Nashorn-linked quasi-object inside a JSObject that fixes the mistakes in the browser JSObject Java implementation. This is coming from a low-level API of mine so I can wrap it inside something ugly if needed to make it work in a more-expected way outside it.

But alternatively, could the jdk.nashorn.internal.runtime.linker class be modified to work around this issue? I ask without attempting to do any understanding of the code, but it appears at a glance that the linker class is already doing a bunch of this stuff. Since it's already JSObject-specific, it seems like it would make sense to insert the code in there if JSObject has known bugs. And interoperability of the two JavaScript implementations is a big win if it works well (which I presume motivated the development of this special-case linker to begin with).

On Fri, Mar 27, 2015 at 10:02 AM, A. Sundararajan <sundararajan.athijegannathan at oracle.com> wrote:

Oops. Actually, there is no JSObject.hasMember/hasSlot to check if a named property or an indexed property exists in a browser JSObject! Unlike Nashorn's own JSObject interface (jdk.nashorn.api.scripting.JSObject) which has hasMember, hasSlot!

So, workaround is to modify the script as follows: var WebEngine = Java.type("javafx.scene.web.WebEngine"); var engine = new WebEngine(); var window = engine.executeScript("window"); // check if property foo exists by "eval" on browser's JS engine! var type = window.eval("typeof this.foo"); if (type == 'undefined') { print("no 'foo' on Window"); } else { print("there is 'foo' of type " + type); } Hope this helps, -Sundar

On Friday 27 March 2015 07:18 PM, A. Sundararajan wrote:

I think I found the issue with this modified script. var WebEngine = Java.type("javafx.scene.web.WebEngine"); var engine = new WebEngine(); var window = engine.executeScript("window"); print(Debug.getClass(window.foo)); print("typeof(window.foo) = " + typeof(window.foo)); if (window.foo) { print("window.foo is truthy"); } We need to run with -J-Dnashorn.debug to enable nashorn debug mode. Debug.getClass gets the Java class of the value. Apparently, browser's JSObject impl. returns a string with the value "undefined" for undefined values! And not a special value or null for undefined... I think nashorn's BrowserJSObjectLinker has to probably call JSObject.hasMember to check existence of a member before calling JSObject.getMember. That appears to be the only way to find out if "undefined" string is due to missing property or not. -Sundar On Friday 27 March 2015 06:22 PM, A. Sundararajan wrote:

Browser's DOM objects (like WebEngine's) implement netscape.javascript.JSObject interface. Such objects are treated specially by nashorn's linker.

http://hg.openjdk.java.net/jdk9/dev/nashorn/file/ca150ddd536e/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java is the dynalink linker that handles such objects. JSObject.getMember, putMember, call are used to provide property, call access seamlessly. Please check out this example: http://hg.openjdk.java.net/jdk9/dev/nashorn/file/ca150ddd536e/samples/browserdom.js So, what you're seeing is a bug in the way that linker works. Let me check out and file a bug. Thanks, -Sundar On Friday 27 March 2015 04:41 PM, David P. Caldwell wrote: So it's very cool, and unexpected, that JavaScript objects obtained from a JavaFX WebEngine show up as something like ordinary Nashorn objects in Nashorn scripts. That's an unexpected bonus (I was planning on using .setMember() and all that stuff from netscape.javascript.JSObject). The objects behave a bit strangely, though. So I've got a couple of bug reports, I guess. Here's a script that demonstrates the ones I've found so far: var WebEngine = Java.type("javafx.scene.web.WebEngine"); var engine = new WebEngine(); var window = engine.executeScript("window"); print("foo = " + window.foo); print("typeof(window.foo) = " + typeof(window.foo)); if (window.foo) { print("window.foo is truthy"); } Output: $ /usr/lib/jvm/jdk1.8.040/bin/jjs -fx nashorn.js foo = undefined typeof(window.foo) = string window.foo is truthy I actually am using a much more complicated embedding that is done from Java, so I can tell you the problem is not in the implementation of the -fx flag. Other than that, I can't see much; I haven't delved into the Nashorn code, let alone whatever magic enables this. -- David.



More information about the nashorn-dev mailing list