Undefined should be part of the exposed nashorn API
Sundararajan Athijegannathan
sundararajan.athijegannathan at oracle.com
Mon Dec 5 06:35:48 UTC 2016
If you want to get undefined value, you can do something like this:
import javax.script.*;
import jdk.nashorn.api.scripting.JSObject;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngine e = new
ScriptEngineManager().getEngineByName("nashorn");
JSObject global =
(JSObject)e.getBindings(ScriptContext.ENGINE_SCOPE);
Object undefined = global.getMember("undefined");
System.out.println(undefined);
e.put("foo", undefined);
System.out.println(e.eval("typeof foo"));
}
}
Thanks,
-Sundar
On 12/1/2016 2:24 AM, Art Fiedler wrote:
> @Sundararajan
>
> I ran into an issue with a JSObject I implemented and some code in LessCSS.
> The team is likely aware by now of a need to
> return Undefined from JSObject's getMember() and possibly call(), and
> getSlot()... You had previously asked a long time ago
> why someone would want to do that and I responded here:
>
> http://stackoverflow.com/questions/30528083/passing-undefined-to-nashorn-javascript-in-scala-java/30533897#30533897
>
> with a comment:
>
> Why pass undefined? Let's say your calling an existing javascript lib (like
> lesscss) that
> calls something like this...
> var variables = options.variables;
> // keep in mind typeof null === 'object' and typeof undefined ===
> 'undefined'
> if (typeof variables === 'object') {
> var keys = Object.keys(variables); //error 'null is not an Object'
> }
> Now to put into perspective, 'options' is an implementation of
> AbstractJSObject... how else
> would you specify in getMember that the member does not exist, returning
> null would throw
> an error when Object.keys() is called.
>
> I used this workaround... because in my sandbox that runs lesscss etc java
> accessibility is removed and I would not be able
> to make the callback...
>
> // Code Fragment
> if (Undefined.getUndefined() == null) {
> // Get the undefined object now, in its own script engine, to avoid
> problems with permissions/security
>
> factory.getScriptEngine().eval("Java.type('io.github.artfiedler.nashorn.Undefined').setUndefined(undefined);");
> }
>
> /**
> * Used to reference the Undefined value used in nashorn.
> *
> * This is a standalone class to avoid a passing a reference
> * to an object like NashornSandbox to javascript that may be
> * exploited in some way unexpected way.
> */
> public final class Undefined
> {
> private static Object undefinedObject;
> public static void setUndefined(Object undefined) { undefinedObject
> = undefined; }
> /**
> * Provides and easy way to get the undefined javascript value used
> by nashorn.
> * This value is not populated until after a NashornSandbox has
> been initialized
> *
> * @return the internal Nashorn object used to reference undefined
> */
> public static Object getUndefined() { return undefinedObject; }
> }
>
> Now using my Undefined class I can do the following in my
> AbstractJSObject... and this will now support the existing lesscss code
> without modifications.
> @Override
> public Object getMember(String name)
> {
> return spill.getOrDefault(name, Undefined.getUndefined());
> }
>
> I know that Undefined is defined at
> jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED &&
> jdk.nashorn.internal.runtime.Undefined.getUndefined()
> and the team may not want to expose those specific classes to the API but I
> believe at least something like this should be done...
>
> @Exported
> public final class ScriptObjectMirror extends AbstractJSObject
> implements Bindings {
> // This already exists...
> public static boolean isUndefined(Object obj) {
> return obj == ScriptRuntime.UNDEFINED;
> }
> // Add...
> public static Object getUndefined() {
> return ScriptRuntime.UNDEFINED;
> }
> ...
> }
>
> -- or --
>
> @Exported
> public interface JSObject
> {
> Object Undefined = ScriptRuntime.UNDEFINED;
> ...
> }
>
> -- or --
>
> @Exported
> public interface JSObject
> {
> Object Undefined = new Object() { @Override public String
> toString() {return "undefined";} };
> ...
> }
> // This would require any usages of JSObject to check for
> JSObject.Undefined coming out of getMember(), call(), getSlot(), eval(),
> newObject()
More information about the nashorn-dev
mailing list