Docs/examples for JSAdapter

Rick Bullotta rick.bullotta at thingworx.com
Tue Oct 22 10:06:19 PDT 2013


I am going to try to mock up some kind of dependency injection based approach that works somewhat like the "wrapper" model on classes that extends JSObject.  The primary change is that I'm going to have to implement the code that performs the "wrapping" each time I access an object or property/function - I'll have to figure out all the places it is needed.  That's the cool part about a wrap factory, which would be fairly easy to add to Nashorn.  Basically whenever an object is accessed, a check is made to see if it is one of the type(s) in the factory list, and if so, call the factory to let it create a wrapper object.  It allows this logic to be confined to one place instead of scattered around everywhere any of those types might be accessed via script.

Anyway, I think I know what I'm up against now.  That's a start. ;-)

-----Original Message-----
From: nashorn-dev-bounces at openjdk.java.net [mailto:nashorn-dev-bounces at openjdk.java.net] On Behalf Of Rick Bullotta
Sent: Tuesday, October 22, 2013 12:54 PM
To: Attila Szegedi
Cc: nashorn-dev at openjdk.java.net
Subject: RE: Docs/examples for JSAdapter

Cool.  Any examples out there in the ether?  

That said, I do think an interface-based approach would be more desirable since it does not force a specific class hierarchy (e.g. must extend JSObject), which could be very problematic in many cases (including ours).

-----Original Message-----
From: Attila Szegedi [mailto:attila.szegedi at oracle.com] 
Sent: Tuesday, October 22, 2013 12:51 PM
To: Rick Bullotta
Cc: A. Sundararajan; nashorn-dev at openjdk.java.net
Subject: Re: Docs/examples for JSAdapter

You should be able to use your own subclasses of jdk.nashorn.api.scripting.JSObject for this purpose.

Attila.

On Oct 22, 2013, at 6:46 PM, Rick Bullotta <rick.bullotta at thingworx.com> wrote:

> Yuck.  Looks like we'll be sticking with Rhino for a while then. 
> 
> I would STRONGLY recommend adding the ability of a Java class developer to implement an interface that provides the functionality I described in my response to Jim.  It is just plain wrong to push complexity to the end user when it can easily be solved in the framework/platform.  To implement that should be rather trivial, to be honest.
> 
> 
> -----Original Message-----
> From: nashorn-dev-bounces at openjdk.java.net [mailto:nashorn-dev-bounces at openjdk.java.net] On Behalf Of A. Sundararajan
> Sent: Tuesday, October 22, 2013 12:33 PM
> To: nashorn-dev at openjdk.java.net
> Subject: Re: Docs/examples for JSAdapter
> 
> No. Nashorn uses wrapperless Java objects. Java objects are exposed to scripts "as is" - no wrapping as 'script objects' as in Rhino.
> 
> It is possible to implement Java interfaces in script (just like it was in Rhino).
> 
> -Sundar
> 
> On Tuesday 22 October 2013 09:32 PM, Rick Bullotta wrote:
>> In Rhino, you register custom adapters in a "wrap factory" that tells the script engine to use these adapters for accessing instances of those classes/types.  What's the analog in Nashorn?  Can custom types implement interfaces that Nashorn will use?
>> 
>> From: Jim Laskey (Oracle) [mailto:james.laskey at oracle.com]
>> Sent: Tuesday, October 22, 2013 11:52 AM
>> To: Rick Bullotta
>> Cc: nashorn-dev at openjdk.java.net
>> Subject: Re: Docs/examples for JSAdapter
>> 
>> In general the Nashorn docs start here. https://wiki.openjdk.java.net/display/Nashorn/Nashorn+Documentation, but as you point out, we seem to be lacking JSAdapter details.  I should start an FAQ.
>> 
>>> From the javadoc (cd make; ant javadoc # ./dist/javadoc/index.html)
>> 
>> 
>> *         public final class NativeJSAdapter
>> 
>> *         extends ScriptObject<file:///\\Volumes\Elephant\Projects\nashorn~jdk8\nashorn\dist\javadoc\jdk\nashorn\internal\runtime\ScriptObject.html>
>> This class is the implementation of the Nashorn-specific global object named JSAdapter. It can be thought of as the Proxy<http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html?is-external=true> equivalent for JavaScript. NativeJSAdapter calls specially named JavaScript methods on an adaptee object when property access/update/call/new/delete is attempted on it. Example:
>> 
>>     var y = {
>> 
>>                 __get__    : function (name) { ... }
>> 
>>                 __has__    : function (name) { ... }
>> 
>>                 __put__    : function (name, value) {...}
>> 
>>                 __call__   : function (name, arg1, arg2) {...}
>> 
>>                 __new__    : function (arg1, arg2) {...}
>> 
>>                 __delete__ : function (name) { ... }
>> 
>>                 __getIds__ : function () { ... }
>> 
>>             };
>> 
>> 
>> 
>>     var x = new JSAdapter(y);
>> 
>> 
>> 
>>     x.i;                        // calls y.__get__
>> 
>>     x.foo();                    // calls y.__call__
>> 
>>     new x();                    // calls y.__new__
>> 
>>     i in x;                     // calls y.__has__
>> 
>>     x.p = 10;                   // calls y.__put__
>> 
>>     delete x.p;                 // calls y.__delete__
>> 
>>     for (i in x) { print(i); }  // calls y.__getIds__
>> 
>> 
>> 
>> JavaScript caller of adapter object is isolated from the fact that the property access/mutation/deletion are really calls to JavaScript methods on adaptee.
>> 
>> JSAdapter constructor can optionally receive an "overrides" object. Properties of overrides object is copied to JSAdapter instance. When user accessed property is one of these, then adaptee's methods like __get__, __put__ etc. are not called for those. This can be used to make certain "preferred" properties that can be accessed in the usual/faster way avoiding proxy mechanism. Example:
>> 
>>      var x = new JSAdapter({ foo: 444, bar: 6546 }) {
>> 
>>           __get__: function(name) { return name; }
>> 
>>       };
>> 
>> 
>> 
>>      x.foo;           // 444 directly retrieved without __get__ call
>> 
>>      x.bar = 'hello'; // "bar" directly set without __put__ call
>> 
>>      x.prop           // calls __get__("prop") as 'prop' is not overridden
>> 
>> 
>> It is possible to pass a specific prototype for JSAdapter instance by passing three arguments to JSAdapter constructor. So exact signature of JSAdapter constructor is as follows:
>> 
>>      JSAdapter([proto], [overrides], adaptee);
>> 
>> 
>> Both proto and overrides are optional - but adaptee is not. When proto is not passed JSAdapter.prototype is used.
>> *
>> As well as the test ./test/script/basic/jsadapter.js
>> 
>> var obj = new JSAdapter() {
>>     __get__: function(name) {
>>         print("getter called for '" + name + "'"); return name;
>>     },
>> 
>>     __put__: function(name, value) {
>>         print("setter called for '" + name + "' with " + value);
>>     },
>> 
>>     __call__: function(name, arg1, arg2) {
>>         print("method '" + name + "' called with " + arg1 + ", " + arg2);
>>     },
>> 
>>     __new__: function(arg1, arg2) {
>>         print("new with " + arg1 + ", " + arg2);
>>     },
>> 
>>     __getIds__: function() {
>>         print("__getIds__ called");
>>         return [ "foo", "bar" ];
>>     },
>> 
>>     __getValues__: function() {
>>         print("__getValues__ called");
>>         return [ "fooval", "barval" ];
>>     },
>> 
>>     __has__: function(name) {
>>         print("__has__ called with '" + name + "'");
>>         return name == "js";
>>     },
>> 
>>     __delete__: function(name) {
>>         print("__delete__ called with '" + name + "'");
>>         return true;
>>     }
>> };
>> 
>> // calls __get__
>> print(obj.foo);
>> 
>> // calls __put__
>> obj.foo = 33;
>> 
>> // calls __call__
>> obj.func("hello", "world");
>> 
>> // calls __new__
>> new obj("hey!", "it works!");
>> 
>> for (i in obj) {
>>     print(i);
>> }
>> 
>> for each (i in obj) {
>>     print(i);
>> }
>> 
>> var x = "foo" in obj;
>> print(x);
>> 
>> var y = "js" in obj;
>> print(y);
>> 
>> print(delete obj.prop);
>> 
>> print(obj["js"]);
>> obj["js"] = "javascript";
>> print(obj["javascript"]);
>> Hope that helps.  Is there a specific question?
>> 
>> Cheers,
>> 
>> -- Jim
>> 
>> On 2013-10-22, at 11:50 AM, Rick Bullotta <rick.bullotta at thingworx.com<mailto:rick.bullotta at thingworx.com>> wrote:
>> 
>> 
>> Hi, all.
>> 
>> I've been searching everywhere for any form of documentation or substantive examples as to how JSAdapter works in Nashorn, as it is an essential piece of the puzzle for many of us who will naturally be migrating from Rhino.
>> 
>> Can anyone provide and additional info?
>> 
>> Thanks,
>> 
>> Rick
>> ThingWorx
>> 
> 



More information about the nashorn-dev mailing list