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