Nashorn JSObject with JDK 9

Florian Beese florian.beese at gmail.com
Fri Nov 18 09:36:36 UTC 2016


Hi together,

I got a question relating the usage of JSObject Interface and
AbstractJSObject class with JDK 9. I hope you can tell me where to look or
whom to talk to.

My problem is, that when I want to access ScriptRuntime.UNDEFINED to be
abled to return "undefined" for members of my object, that do not exist, I
cannot access that class attribute as the ScriptRuntime class is not
exported. How shall I then tell the engine, that a member does not exist?
(null is not an option as this is not compatible to normal JS behavior).

See the following code example, which runs with JDK 8, but not with JDK 9
anymore.

Thanks in advance and best regards
Florian

============ Code Example ==============

package com.your.test.package;

import static org.junit.Assert.assertEquals;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.junit.Test;

import jdk.nashorn.api.scripting.AbstractJSObject;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;

/* see the JSMapWrapper.getMember() method to understand the problem */
public class NashornWrapMapTest {

@SuppressWarnings("restriction")
private class JSMapWrapper extends AbstractJSObject implements JSObject {
protected Map<String, Object> wrappedMap = null;

public JSMapWrapper(Map<String, Object> mapToWrap) {
wrappedMap = mapToWrap;
}

public Map<String, Object> getMap() {
return wrappedMap;
}

@Override
public Object call(Object thiz, Object... args) { return super.call(thiz,
args); }

@Override
public Object newObject(Object... args) { return super.newObject(args); }

@Override
public Object eval(String s) { return super.eval(s); }

@Override
public Object getMember(String name) {
if (!wrappedMap.containsKey(name)) {
/* HERE is the problem with JDK as ScriptRuntime is not Exported */
return ScriptRuntime.UNDEFINED;
}
return wrappedMap.get(name);
}

@Override
public Object getSlot(int index) { return null; }

@Override
public boolean hasMember(String name) { return
wrappedMap.containsKey(name); }

@Override
public boolean hasSlot(int slot) { return false; }
@Override
public void removeMember(String name) { wrappedMap.remove(name); }

@Override
public void setMember(String name, Object value) { wrappedMap.put(name,
value); }

@Override
public void setSlot(int index, Object value) { super.setSlot(index, value);
}

@Override
public Set<String> keySet() { return wrappedMap.keySet(); }

@Override
public Collection<Object> values() { return wrappedMap.values(); }

@Override
public boolean isInstance(Object instance) { return
super.isInstance(instance); }

@Override
public boolean isInstanceOf(Object clazz) { return
super.isInstanceOf(clazz); }

@Override
public String getClassName() { return super.getClassName(); }

@Override
public boolean isFunction() { return false; }

@Override
public boolean isStrictFunction() { return false; }

@Override
public double toNumber() { return super.toNumber(); }

@Override
public boolean isArray() { return false; }

@Override
public String toString() {
String s = "Object(Map) : {";
boolean isFirst = true;
for (Map.Entry<String, Object> entry : wrappedMap.entrySet()) {
if (!isFirst) {
s += ", ";
isFirst = false;
}
s += entry.getKey() + ": " + entry.getValue().toString();
}
s += "}";
return s;
}
}

@Test
public void testUndefinedValue() throws ScriptException,
NoSuchMethodException {
final ScriptEngine engine = new
ScriptEngineManager().getEngineByName("nashorn");
final Compilable compilable = (Compilable) engine;
final Invocable invocable = (Invocable) engine;

final String okReturn = "OK: did not contain testKey2";

final String scriptFunction = "function testMap(map) { "
+ "if (typeof map.testKey2 === 'undefined') { return '" + okReturn
+ "'; } return 'ERROR: should not happen: ' + map.testKey; };";
final CompiledScript compiled = compilable.compile(scriptFunction);

compiled.eval();

Map<String, Object> map = new HashMap<String, Object>();
map.put("testKey", "testVal"); //change the key to testKey2 to see the test
failing

JSMapWrapper wrapper = new JSMapWrapper(map);

String ret = (String) invocable.invokeFunction("testMap", wrapper);

assertEquals(okReturn, ret);
}
}


More information about the nashorn-dev mailing list