Hi, Filed a bug: https://bugs.openjdk.java.net/browse/JDK-8157160
Thanks, -Sundar On 5/13/2016 8:16 PM, Eric Pederson wrote: > Hi Sundar - > > It would be helpful for sure. We use JSON for serialization and > debugging a lot. Also if it worked it could simplify our > custom ScriptObjectMirror -> native object conversion logic from 30 > lines down to JSON.parse(JSON.stringify(scriptObjMirror)) :). > > Besides the JSON stuff our biggest problem has been > ScriptObjectMirrors being treated like regular objects and passed down > call chains and then either throwing exceptions or silently failing > and it's hard to figure out why. Junior developers get completely > baffled. We have solved the problem with the commonjs/require loading > pattern on the script loading side and the proxy pattern on the Java > calling side. It would be nice to have official solutions for these > but it's not urgent. It might be something worth adding to the > documentation. > > Thanks, > > > > -- Eric > > On Fri, May 13, 2016 at 12:30 AM, Sundararajan Athijegannathan > <sundararajan.athijegannat...@oracle.com > <mailto:sundararajan.athijegannat...@oracle.com>> wrote: > > Hi Eric, > > That commonjs/require loading pattern is not bad [wrapping eval'ed > code inside a function]. If your loaded scripts are (somewhat) > well-behaved, it does solve the problem of global namespace pollution. > > Yes, ScriptObjectMirrors are not uniformly treated like > ScriptObject everywhere. But, I'm not sure how far we can fix > that :( Is JSON handling (w.r.t ScriptObjectMirror) your main pain > point? We *may* be able to address that. > > Thanks, > > -Sundar > > > On 5/12/2016 11:10 PM, Eric Pederson wrote: >> Hi Sundar: >> >> 1. I investigated loadWithNewGlobal because it looked promising >> for this use case. Say you use loadWithNewGlobal to load a >> function. If you call the loaded function and it returns an >> object or array the caller gets a ScriptObjectMirror. The >> problems with a ScriptObjectMirror "object" are: >> >> * Cannot call Object methods like keys or getOwnPropertyNames. >> You get an exception: TypeError: cannot call undefined. To >> iterate over the properties you must use a for in loop. >> * Cannot convert ScriptObjectMirror to JSON using >> JSON.stringify. It returns undefined. >> >> If the function loaded with loadWithNewGlobal returns an array >> then things are better. Interestingly you can call most Array >> methods (like forEach and map) on a ScriptObjectMirror "array". >> But JSON.stringify also returns undefined. >> >> I did find one issue with an array returned by a >> loadWithNewGlobal loaded function - calling sort with a >> comparator. For example, if the loaded function returned >> testArray, a ScriptObjectMirror "array": >> >> *var **/sorted /*= */testArray/*.sort(*function*(a, b) { >> >> *return *a - b; }); >> >> >> >> throws an exception_: _TypeError: function(a, b) { return a - >> b; } is not a function. >> >> >> These were the same "mutant" issues that we also saw with >> JSObjects returned by Java methods. >> >> >> The hack that we are using now to load code without effecting the >> global namespace is the same one discussed in this thread: >> >> http://thread.gmane.org/gmane.comp.java.openjdk.nashorn.devel/1722. >> >> >> The code that we are using is copied/adapted from Vertx (thanks, >> Tim!): >> >> >> function loadEval(path) { >> >> *var *dir = *new **/File/*(path).getParent(); >> >> *var *body = /readFile/(path); >> >> *var *moduleFunc = >> >> *"function(exports, module, require, __filename, >> __dirname){" *+ body + *"**\n**}**\n**//# sourceURL=" *+ path; >> >> >> *try {* >> >> *var *func = eval(moduleFunc); >> >> } *catch *(ex) { >> >> *if *(ex *instanceof **SyntaxError*) { >> >> /// WARNING! Large pile of Yak hair ahead! >> / >> >> / /*var *ne = ex.nashornException; >> >> *var *cause = ne.cause; >> >> *var *msg = cause.message.replace(*"<eval>"*, file); >> >> *var *lineNumber = cause.*lineNumber;* >> >> console.log(*"ERROR: " *+ msg + *" in file " *+ file >> + *" at line " *+ lineNumber); >> } >> >> *throw *ex; >> } >> >> *var *module = { *exports*: {} }; >> >> func(module.*exports*, module, require, path, dir); >> >> *return *module.*exports*; >> >> } >> >> >> This seems like a hack to me - but I'm coming from the Java world >> so this may be par for the course in Javascript-land :) Hack or >> no, it is the best of both worlds: it does not change the global >> namespace, yet the code that it returns lives in the global >> context, so if you call a loaded function it will return a native >> object, not a ScriptObjectMirror. >> >> >> We'd like to have a built-in equivalent of this >> loadEvalfunction. It doesn't need to use those specific >> arguments (export, module, etc), but you must be able to pass >> arguments in to provide a context to the loaded code. >> >> >> Alternatively if you could make ScriptObjectMirrors 100% >> compatible with native objects that would work too. Then we >> could use loadWithNewGlobal. >> >> >> 2. The problem that we are having with objects returned by Java >> methods is the same as what I described above because the >> returned JSObjects are seen as ScriptObjectMirrors by the calling >> Javascript code. >> >> >> What we are doing now is wrapping each Java object with a >> Javascript proxy. When you call the proxy it calls the >> corresponding Java method, then converts the returned >> ScriptObjectMirrorinto a native JS object using a custom >> conversion function. >> >> >> What would be nice for this use case is a standard function to >> convert ScriptObjectMirrors to native JS objects (what I was >> calling asJSONCompatible below). Or if ScriptObjectMirrors were >> 100% compatible that would be even better - we could get rid of >> our JS proxy objects. >> >> >> I'm happy to file some enhancement requests. Though it seems >> like the bug trackers are read-only to the general public though, >> how would I get access? >> >> >> Thanks, >> >> >> >> -- Eric >> >> On Thu, May 12, 2016 at 12:36 AM, Sundararajan Athijegannathan >> <sundararajan.athijegannat...@oracle.com >> <mailto:sundararajan.athijegannat...@oracle.com>> wrote: >> >> Hi, >> >> Thanks for your comments! >> >> Making comments on forthcoming JDK releases is hard :) >> Whatever I'm >> saying now, may not happen - the usual disclaimer applies. >> >> No, we expect that only a subset of ES6 features will be >> implemented for >> Java 9. >> >> 1. On loading definitions without changing global namespace: >> you meant >> current global namespace? loadWithNewGlobal creates a new >> global and >> loads definitions into that. >> >> Would that be useful for you? or anything else? Which hack you're >> referring to? Please file an enhancement with your requirements. >> >> 2. on JSON: Again, will you please provide a simple test case >> and/or >> file an enhancement with requirements? >> >> Thanks, >> -Sundar >> >> On 5/12/2016 12:56 AM, Eric Pederson wrote: >> > I've been noticing the Java 9 ES6 features tweeted by >> @sundararajan_a >> > <https://twitter.com/sundararajan_a>. Looks awesome! Will >> there be full >> > ES6 support in Java 9? >> > >> > There are a couple of other things we would love to see in >> the updated >> > Nashorn: >> > >> > 1. We've been using the same hack that you recommended to >> Tim Fox for >> > loading functions without changing the global namespace - >> the Avatar/js >> > CommonJS/require hack. It would be great if this was >> supported natively in >> > Nashorn via a new loadXXX(). >> > >> > 2. It would be also be great to have the inverse of >> asJSONCompatible for a) >> > JSObjects returned by Java code and b) objects from other >> scopes. Our name >> > for ScriptObjectMirrors in Javascript code is "mutant >> objects": they look >> > like regular JS objects but they are missing most of their >> DNA, and you >> > don't realize until you get an exception or silent failure >> somewhere down >> > the call chain where it's difficult to figure out why :) >> > >> > Anyway, the upcoming stuff looks great! >> > >> > Thanks, >> > >> > -- Eric >> >> > >