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()