Problem with interoperability with JavaFX WebEngine
A. Sundararajan
sundararajan.athijegannathan at oracle.com
Mon Mar 30 02:49:40 UTC 2015
Hi,
Without doing another "eval" call on browser's JS engine, I can''t think
of a way to know if a property is missing in the browser's object or
not. Making an "eval" call before every property "get", appears
overkill! I think client code mostly would access "properties know to
exist" - in which case the current scheme is fine. For border cases,
client code has to do the check (by 'eval') before doing property get.
Thanks,
-Sundar
On Friday 27 March 2015 10:21 PM, David P. Caldwell wrote:
> 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