Problem with interoperability with JavaFX WebEngine
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/browser_dom.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.0_40/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