Hi Tal Liron,
Sorry about missing reply for this email. I somehow remember replying
similar nashorn internal usage email.
It is difficult maintain all of jdk.nashorn.internal.* between versions.
Also, with security manager around, jdk.nashorn.internal.* are not
accessible without explicit 'package access' RuntimePermission. In
addition, with jdk9, nashorn module exports only jdk.nashorn.api.*
packages. i.e., even without any security manager, user code won't be
able to access nashorn internal implementation classes. It is possible
to use jdk.nashorn.api.scripting.JSObject to get constructors and create
objecs.
JSObject numberConstructor = (JSObject) engine.eval("Number");
JSObject numberObj = numberConstructor.newObject();
Is it not possible to work with these? Please check out latest 8u-dev
code. Mostly explicit wrap/unwrap won't be required from user's code.
Thanks,
-Sundar
On 10/15/2015 10:21 PM, Tal Liron wrote:
Hey guys, nobody ever responded to my message...
Do you really think that my usage of these internal Nashorn APIs is so
unwarranted?
I tried to prove that some useful libraries need to use Nashorn APIs
that some of you insist should not be made public.
On 07/06/2015 09:10 PM, Tal Liron wrote:
Hi Atilla (and Sundar and everyone else, really),
You asked which Nashorn APIs I'm using that are not documented. I
will reply in full detail.
For the BSON/JSON codecs, the most important thing is to access the
NativeBoolean, NativeNumber, NativeArray, ConsString, Undefined,
etc., classes. This allows the codecs to check for these classes
incoming, and also to easily create instances of them using their
constructor() static method.
ScriptObject has no constructor(), so I use
Global.newEmptyInstance(). (By the way: NativeDate and NativeArray
name the method construct() instead of constructor(). I assume this
is a consistency mistake.)
But I also need to access their data. This means get()/set() for
NativeScriptObject and NativeArray, getOwnKeys(), getArray() (which
means I need access to the ArrayData class), and also getTime() for
NativeData. NativeRegExp is a bit harder, but I use get("source"),
get("multiline"), etc.
(In Rhino, some of these classes are actually private! This required
an awkward workaround: I do a string equality check on the classname.
That's neither efficient nor portable, though more "dynamic", I
guess. Also, for these classes I can use Context.newObject() to
create instances by JS name, for example "RegExp". Then I can do
ScriptableObject.callMethod() to access their internals. So, there
are workarounds to not being to able to access them.)
ScriptObjectMirror is awkward. Though it's stable and documented, the
issue with unwrap() is that it needs a global. Documented, but of
course unclear what to do! For me, this actually means calling
Context.getGlobal(), which is not publicly documented. (Another issue
is that, of course, unwrap won't work for other globals. This has
created difficulties in some threaded environments in which multiple
globals are used intentionally. More on that below.)
So much for BSON/JSON. The Scripturian implementation of Nashorn is
much more complex. As you may know, Scripturian is a rethinking of
and alternative to JSR-223, so it has to do much of the same work.
Scripturian works by purposely creating different global instances
for each "execution context" (which *can* be a thread, but doesn't
have to be: it's an abstraction over, well, execution contexts). I
use Context.createGlobal(), and set it via Context.setGlobal().
We then need to compile scripts in the Context, so I use
Source.sourceFor() and Context.compileScript(), which returns a
ScriptFunction, so I also need access to that. Compilations errors
are via Context.getErrorManager(), so I need access to ErrorManager.
To run the scripts, I use ScriptRuntime.apply(). A small fix I need
to add is that Nashorn's NativeArray does not support java.util.List,
so if an array is returned from apply(), I call NativeJava.to() to
get list access. Thats's just a bit friendlier for users of
Scripturian, who are otherwise agnostic about implementation specifics.
There's an important issue here: remember, there might be many
different globals, but of course I want them all to use the same code
cache, which is stored in the Context. So, I use one singleton
Context and switch globals via Context.setGlobal(). To create a
Context, I also need access to Options. A limitation in Nashorn is
that I can't change stdout and stderr after I create the Context
(Scripturian allows different onces per ExecutionContext), so my
workaround is to use a custom Writer wrapper class that underneath
delegates to the correct "real" Writers (I use the same mechanism for
a few other Scripturian language engines, too).
I grumbled here before that I have no programmatic access to the code
cache. Behind the scenes, ScriptFunction might retrieve from the
cache instead of being compiled. I can control the cache base
location via the "nashorn.persistent.code.cache" system property, but
it's unfortunate that I can't control the structure and naming the
way I can with other languages supported by Scripturian. In
particular, the problem is that it's a global property for the whole
JVM, whereas compilation and caching location is ideally controlled
per ExecutionContext in Scripturian. This makes Nashorn support in
Scripturian a bit more limited.
Finally, for errors during execution, I use NashornException
(documented!) to extract specific information into Scripturian's more
generic ExecutionException.
Small extras: I use Version.version() and
NashornScriptEngineFactory.getLanguageVersion() to get version data.
I think that's everything! Of course, I also had to "reverse
engineer" much of this (=read a lot of code) and work around many
quirks (and big differences to Rhino's implementation) before
streamlining it down to just these few classes. (I tried to work
around the caching limitations, but gave up due to its complexity.
Also, I think some of the key classes I would need are private.) I
did my best not to delve to much into internals, but I hope I made it
clear to you that it would have been impossible to achieve all the
above goals without it.
-Tal
On 07/06/2015 04:18 AM, Attila Szegedi wrote:
What APIs are you using, BTW? Just curious if I can suggest an
alternative approach, or even consider if something you use should
be publicly supported.