8006584: improve variable handling in NashornScriptEngine
Reviewed-by: jlaskey, hannesw
This commit is contained in:
parent
cef1f6c50b
commit
7784f11d28
@ -28,15 +28,11 @@ package jdk.nashorn.api.scripting;
|
|||||||
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
|
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
|
||||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||||
import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
@ -140,6 +136,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
}
|
}
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -156,23 +154,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
return evalImpl(script.toCharArray(), ctxt);
|
return evalImpl(script.toCharArray(), ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: This is not exactly right. Script execution should actually
|
|
||||||
* put the variables in ENGINE_SCOPE bindings. But, it is difficult
|
|
||||||
* (not possible?) with the way ScriptObject is implemented. So, for now
|
|
||||||
* giving access to script variables by accessing it from "globals". This
|
|
||||||
* way at least engine.get("foo") will work whenever "foo" is a global var
|
|
||||||
* defined by eval'ed scripts.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object get(final String key) {
|
|
||||||
Object value = super.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
value = ScriptObjectMirror.wrap(global.get(key), global);
|
|
||||||
}
|
|
||||||
return (value == UNDEFINED) ? null : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ScriptEngineFactory getFactory() {
|
public ScriptEngineFactory getFactory() {
|
||||||
return factory;
|
return factory;
|
||||||
@ -306,23 +287,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
}
|
}
|
||||||
|
|
||||||
value = ScriptObjectMirror.unwrap(value, global);
|
value = ScriptObjectMirror.unwrap(value, global);
|
||||||
|
|
||||||
if (value instanceof Method) {
|
|
||||||
final Method method = (Method) value;
|
|
||||||
final int mods = method.getModifiers();
|
|
||||||
if (Modifier.isStatic(mods) && Modifier.isPublic(mods)) {
|
|
||||||
value = MH.find((Method)value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof MethodHandle) {
|
|
||||||
value = ((GlobalObject)global).newScriptFunction(name, (MethodHandle)value, null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(value instanceof ScriptFunction)) {
|
|
||||||
typeError(global, "not.a.function", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof ScriptFunction) {
|
if (value instanceof ScriptFunction) {
|
||||||
return ScriptObjectMirror.unwrap(ScriptRuntime.apply((ScriptFunction)value, global, args), global);
|
return ScriptObjectMirror.unwrap(ScriptRuntime.apply((ScriptFunction)value, global, args), global);
|
||||||
}
|
}
|
||||||
@ -359,13 +323,12 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
// scripts should see "context" and "engine" as variables
|
// scripts should see "context" and "engine" as variables
|
||||||
private void setContextVariables(final ScriptContext ctxt) {
|
private void setContextVariables(final ScriptContext ctxt) {
|
||||||
ctxt.setAttribute("context", ctxt, ScriptContext.ENGINE_SCOPE);
|
ctxt.setAttribute("context", ctxt, ScriptContext.ENGINE_SCOPE);
|
||||||
// current ScriptContext exposed as "context"
|
|
||||||
global.set("context", ctxt, false);
|
global.set("context", ctxt, false);
|
||||||
Object args = ctxt.getAttribute("arguments");
|
Object args = ScriptObjectMirror.unwrap(ctxt.getAttribute("arguments"), global);
|
||||||
// if no arguments passed, make it empty array
|
if (args == null || args == UNDEFINED) {
|
||||||
if (args == null) {
|
|
||||||
args = ScriptRuntime.EMPTY_ARRAY;
|
args = ScriptRuntime.EMPTY_ARRAY;
|
||||||
}
|
}
|
||||||
|
// if no arguments passed, expose it
|
||||||
args = ((GlobalObject)global).wrapAsObject(args);
|
args = ((GlobalObject)global).wrapAsObject(args);
|
||||||
global.set("arguments", args, false);
|
global.set("arguments", args, false);
|
||||||
}
|
}
|
||||||
@ -382,7 +345,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptObject sobj;
|
ScriptObject sobj;
|
||||||
Object value;
|
Object value = null;
|
||||||
|
|
||||||
self = ScriptObjectMirror.unwrap(self, global);
|
self = ScriptObjectMirror.unwrap(self, global);
|
||||||
|
|
||||||
@ -394,25 +357,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
self = global;
|
self = global;
|
||||||
sobj = global;
|
sobj = global;
|
||||||
value = sobj.get(name);
|
value = sobj.get(name);
|
||||||
} else {
|
|
||||||
// Find the java method and make a ScriptFunction of it.
|
|
||||||
final Method[] methods = self.getClass().getMethods();
|
|
||||||
Method target = null;
|
|
||||||
|
|
||||||
for (final Method mth : methods) {
|
|
||||||
// choose the right overload by number of arguments -- don't
|
|
||||||
// care overload resolution for now..
|
|
||||||
if (mth.getName().equals(name) &&
|
|
||||||
mth.getParameterTypes().length == args.length) {
|
|
||||||
target = mth;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (target == null) {
|
|
||||||
throw new NoSuchMethodException(name);
|
|
||||||
}
|
|
||||||
final GlobalObject gobj = (GlobalObject) global;
|
|
||||||
value = gobj.newScriptFunction(name, MH.find(target), null, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value instanceof ScriptFunction) {
|
if (value instanceof ScriptFunction) {
|
||||||
@ -423,7 +367,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
throwAsScriptException(e);
|
throwAsScriptException(e);
|
||||||
throw new AssertionError("should not reach here");
|
throw new AssertionError("should not reach here");
|
||||||
}
|
}
|
||||||
return ScriptObjectMirror.wrap(res, global);
|
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(res, global));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NoSuchMethodException(name);
|
throw new NoSuchMethodException(name);
|
||||||
@ -461,8 +405,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object res = ScriptRuntime.apply(script, global);
|
Object res = ScriptRuntime.apply(script, global);
|
||||||
res = ScriptObjectMirror.wrap(res, global);
|
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(res, global));
|
||||||
return (res == UNDEFINED) ? null : res;
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
throwAsScriptException(e);
|
throwAsScriptException(e);
|
||||||
throw new AssertionError("should not reach here");
|
throw new AssertionError("should not reach here");
|
||||||
@ -516,7 +459,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
|||||||
setNashornGlobal(global);
|
setNashornGlobal(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
setContextVariables(ctxt);
|
|
||||||
return nashornContext.compileScript(source, global, nashornContext._strict);
|
return nashornContext.compileScript(source, global, nashornContext._strict);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
throwAsScriptException(e);
|
throwAsScriptException(e);
|
||||||
|
@ -35,6 +35,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import javax.script.Bindings;
|
||||||
import jdk.nashorn.internal.runtime.Context;
|
import jdk.nashorn.internal.runtime.Context;
|
||||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||||
@ -43,9 +44,10 @@ import netscape.javascript.JSObject;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Mirror object that wraps a given ScriptObject instance. User can
|
* Mirror object that wraps a given ScriptObject instance. User can
|
||||||
* access ScriptObject via the java.util.Map interface.
|
* access ScriptObject via the javax.script.Bindings interface or
|
||||||
|
* netscape.javascript.JSObject interface.
|
||||||
*/
|
*/
|
||||||
final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
final class ScriptObjectMirror extends JSObject implements Bindings {
|
||||||
private final ScriptObject sobj;
|
private final ScriptObject sobj;
|
||||||
private final ScriptObject global;
|
private final ScriptObject global;
|
||||||
|
|
||||||
@ -146,12 +148,20 @@ final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getMember(final String name) {
|
public Object getMember(final String name) {
|
||||||
return get(name);
|
return inGlobal(new Callable<Object>() {
|
||||||
|
@Override public Object call() {
|
||||||
|
return wrap(sobj.get(name), global);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getSlot(final int index) {
|
public Object getSlot(final int index) {
|
||||||
return get(Integer.valueOf(index));
|
return inGlobal(new Callable<Object>() {
|
||||||
|
@Override public Object call() {
|
||||||
|
return wrap(sobj.get(index), global);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -166,7 +176,12 @@ final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSlot(final int index, final Object value) {
|
public void setSlot(final int index, final Object value) {
|
||||||
put(Integer.valueOf(index), wrap(value, Context.getGlobal()));
|
inGlobal(new Callable<Void>() {
|
||||||
|
@Override public Void call() {
|
||||||
|
sobj.set(index, unwrap(value, global), global.getContext()._strict);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -175,7 +190,8 @@ final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
|||||||
@Override public Object call() {
|
@Override public Object call() {
|
||||||
sobj.clear();
|
sobj.clear();
|
||||||
return null;
|
return null;
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -183,7 +199,8 @@ final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
|||||||
return inGlobal(new Callable<Boolean>() {
|
return inGlobal(new Callable<Boolean>() {
|
||||||
@Override public Boolean call() {
|
@Override public Boolean call() {
|
||||||
return sobj.containsKey(unwrap(key, global));
|
return sobj.containsKey(unwrap(key, global));
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -191,19 +208,20 @@ final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
|||||||
return inGlobal(new Callable<Boolean>() {
|
return inGlobal(new Callable<Boolean>() {
|
||||||
@Override public Boolean call() {
|
@Override public Boolean call() {
|
||||||
return sobj.containsValue(unwrap(value, global));
|
return sobj.containsValue(unwrap(value, global));
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Map.Entry<Object, Object>> entrySet() {
|
public Set<Map.Entry<String, Object>> entrySet() {
|
||||||
return inGlobal(new Callable<Set<Map.Entry<Object, Object>>>() {
|
return inGlobal(new Callable<Set<Map.Entry<String, Object>>>() {
|
||||||
@Override public Set<Map.Entry<Object, Object>> call() {
|
@Override public Set<Map.Entry<String, Object>> call() {
|
||||||
final Iterator<String> iter = sobj.propertyIterator();
|
final Iterator<String> iter = sobj.propertyIterator();
|
||||||
final Set<Map.Entry<Object, Object>> entries = new HashSet<>();
|
final Set<Map.Entry<String, Object>> entries = new HashSet<>();
|
||||||
|
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
final Object key = wrap(iter.next(), global);
|
final String key = iter.next();
|
||||||
final Object value = wrap(sobj.get(key), global);
|
final Object value = translateUndefined(wrap(sobj.get(key), global));
|
||||||
entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));
|
entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,49 +232,58 @@ final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get(final Object key) {
|
public Object get(final Object key) {
|
||||||
return inGlobal(new Callable<Object>() { @Override public Object call() {
|
return inGlobal(new Callable<Object>() {
|
||||||
return wrap(sobj.get(key), global);
|
@Override public Object call() {
|
||||||
}});
|
return translateUndefined(wrap(sobj.get(key), global));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return inGlobal(new Callable<Boolean>() { @Override public Boolean call() {
|
return inGlobal(new Callable<Boolean>() {
|
||||||
return sobj.isEmpty();
|
@Override public Boolean call() {
|
||||||
}});
|
return sobj.isEmpty();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Object> keySet() {
|
|
||||||
return inGlobal(new Callable<Set<Object>>() { @Override public Set<Object> call() {
|
|
||||||
final Iterator<String> iter = sobj.propertyIterator();
|
|
||||||
final Set<Object> keySet = new HashSet<>();
|
|
||||||
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
keySet.add(wrap(iter.next(), global));
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return Collections.unmodifiableSet(keySet);
|
|
||||||
}});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object put(final Object key, final Object value) {
|
public Set<String> keySet() {
|
||||||
|
return inGlobal(new Callable<Set<String>>() {
|
||||||
|
@Override public Set<String> call() {
|
||||||
|
final Iterator<String> iter = sobj.propertyIterator();
|
||||||
|
final Set<String> keySet = new HashSet<>();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
keySet.add(iter.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableSet(keySet);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object put(final String key, final Object value) {
|
||||||
return inGlobal(new Callable<Object>() {
|
return inGlobal(new Callable<Object>() {
|
||||||
@Override public Object call() {
|
@Override public Object call() {
|
||||||
return sobj.put(unwrap(key, global), unwrap(value, global));
|
return sobj.put(key, unwrap(value, global));
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putAll(final Map<?, ?> map) {
|
public void putAll(final Map<? extends String, ? extends Object> map) {
|
||||||
final boolean strict = sobj.getContext()._strict;
|
final boolean strict = sobj.getContext()._strict;
|
||||||
inGlobal(new Callable<Object>() { @Override public Object call() {
|
inGlobal(new Callable<Object>() {
|
||||||
for (final Map.Entry<?, ?> entry : map.entrySet()) {
|
@Override public Object call() {
|
||||||
sobj.set(unwrap(entry.getKey(), global), unwrap(entry.getValue(), global), strict);
|
for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
|
||||||
|
sobj.set(entry.getKey(), unwrap(entry.getValue(), global), strict);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
});
|
||||||
}});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -279,16 +306,22 @@ final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Object> values() {
|
public Collection<Object> values() {
|
||||||
return inGlobal(new Callable<Collection<Object>>() { @Override public Collection<Object> call() {
|
return inGlobal(new Callable<Collection<Object>>() {
|
||||||
final List<Object> values = new ArrayList<>(size());
|
@Override public Collection<Object> call() {
|
||||||
final Iterator<Object> iter = sobj.valueIterator();
|
final List<Object> values = new ArrayList<>(size());
|
||||||
|
final Iterator<Object> iter = sobj.valueIterator();
|
||||||
|
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
values.add(wrap(iter.next(), global));
|
values.add(wrap(iter.next(), global));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(values);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Collections.unmodifiableList(values);
|
static Object translateUndefined(Object obj) {
|
||||||
}});
|
return (obj == ScriptRuntime.UNDEFINED)? null : obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object wrap(final Object obj, final ScriptObject homeGlobal) {
|
static Object wrap(final Object obj, final ScriptObject homeGlobal) {
|
||||||
|
@ -27,6 +27,7 @@ package jdk.nashorn.api.scripting;
|
|||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
import static org.testng.Assert.assertNotNull;
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertFalse;
|
||||||
import static org.testng.Assert.assertTrue;
|
import static org.testng.Assert.assertTrue;
|
||||||
import static org.testng.Assert.fail;
|
import static org.testng.Assert.fail;
|
||||||
|
|
||||||
@ -40,13 +41,13 @@ import javax.script.Bindings;
|
|||||||
import javax.script.Compilable;
|
import javax.script.Compilable;
|
||||||
import javax.script.CompiledScript;
|
import javax.script.CompiledScript;
|
||||||
import javax.script.Invocable;
|
import javax.script.Invocable;
|
||||||
|
import javax.script.ScriptContext;
|
||||||
import javax.script.ScriptEngine;
|
import javax.script.ScriptEngine;
|
||||||
import javax.script.ScriptEngineFactory;
|
import javax.script.ScriptEngineFactory;
|
||||||
import javax.script.ScriptEngineManager;
|
import javax.script.ScriptEngineManager;
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
import jdk.nashorn.internal.runtime.Version;
|
import jdk.nashorn.internal.runtime.Version;
|
||||||
import netscape.javascript.JSObject;
|
import netscape.javascript.JSObject;
|
||||||
import org.testng.Assert;
|
|
||||||
import org.testng.TestNG;
|
import org.testng.TestNG;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
@ -107,8 +108,8 @@ public class ScriptEngineTest {
|
|||||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
assertEquals(true,e.eval("arguments instanceof Array"));
|
assertEquals(e.eval("arguments instanceof Array"), true);
|
||||||
assertEquals(true, e.eval("arguments.length == 0"));
|
assertEquals(e.eval("arguments.length == 0"), true);
|
||||||
} catch (final Exception exp) {
|
} catch (final Exception exp) {
|
||||||
exp.printStackTrace();
|
exp.printStackTrace();
|
||||||
fail(exp.getMessage());
|
fail(exp.getMessage());
|
||||||
@ -123,13 +124,13 @@ public class ScriptEngineTest {
|
|||||||
|
|
||||||
final ScriptEngineFactory fac = e.getFactory();
|
final ScriptEngineFactory fac = e.getFactory();
|
||||||
|
|
||||||
assertEquals("ECMAScript", fac.getLanguageName());
|
assertEquals(fac.getLanguageName(), "ECMAScript");
|
||||||
assertEquals("javascript", fac.getParameter(ScriptEngine.NAME));
|
assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript");
|
||||||
assertEquals("ECMA - 262 Edition 5.1", fac.getLanguageVersion());
|
assertEquals(fac.getLanguageVersion(), "ECMA - 262 Edition 5.1");
|
||||||
assertEquals("Oracle Nashorn", fac.getEngineName());
|
assertEquals(fac.getEngineName(), "Oracle Nashorn");
|
||||||
assertEquals(Version.version(), fac.getEngineVersion());
|
assertEquals(fac.getEngineVersion(), Version.version());
|
||||||
assertEquals("print(context)", fac.getOutputStatement("context"));
|
assertEquals(fac.getOutputStatement("context"), "print(context)");
|
||||||
assertEquals("javascript", fac.getParameter(ScriptEngine.NAME));
|
assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript");
|
||||||
|
|
||||||
boolean seenJS = false;
|
boolean seenJS = false;
|
||||||
for (String ext : fac.getExtensions()) {
|
for (String ext : fac.getExtensions()) {
|
||||||
@ -138,9 +139,9 @@ public class ScriptEngineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(true, seenJS);
|
assertEquals(seenJS, true);
|
||||||
String str = fac.getMethodCallSyntax("obj", "foo", "x");
|
String str = fac.getMethodCallSyntax("obj", "foo", "x");
|
||||||
assertEquals("obj.foo(x)", str);
|
assertEquals(str, "obj.foo(x)");
|
||||||
|
|
||||||
boolean seenNashorn = false, seenJavaScript = false, seenECMAScript = false;
|
boolean seenNashorn = false, seenJavaScript = false, seenECMAScript = false;
|
||||||
for (String name : fac.getNames()) {
|
for (String name : fac.getNames()) {
|
||||||
@ -151,9 +152,9 @@ public class ScriptEngineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(true, seenNashorn);
|
assertTrue(seenNashorn);
|
||||||
assertEquals(true, seenJavaScript);
|
assertTrue(seenJavaScript);
|
||||||
assertEquals(true, seenECMAScript);
|
assertTrue(seenECMAScript);
|
||||||
|
|
||||||
boolean seenAppJS = false, seenAppECMA = false, seenTextJS = false, seenTextECMA = false;
|
boolean seenAppJS = false, seenAppECMA = false, seenTextJS = false, seenTextECMA = false;
|
||||||
for (String mime : fac.getMimeTypes()) {
|
for (String mime : fac.getMimeTypes()) {
|
||||||
@ -165,10 +166,10 @@ public class ScriptEngineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(true, seenAppJS);
|
assertTrue(seenAppJS);
|
||||||
assertEquals(true, seenAppECMA);
|
assertTrue(seenAppECMA);
|
||||||
assertEquals(true, seenTextJS);
|
assertTrue(seenTextJS);
|
||||||
assertEquals(true, seenTextECMA);
|
assertTrue(seenTextECMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -186,9 +187,9 @@ public class ScriptEngineTest {
|
|||||||
e.eval("print('hello)");
|
e.eval("print('hello)");
|
||||||
fail("script exception expected");
|
fail("script exception expected");
|
||||||
} catch (final ScriptException se) {
|
} catch (final ScriptException se) {
|
||||||
assertEquals(1, se.getLineNumber());
|
assertEquals(se.getLineNumber(), 1);
|
||||||
assertEquals(13, se.getColumnNumber());
|
assertEquals(se.getColumnNumber(), 13);
|
||||||
assertEquals("myfile.js", se.getFileName());
|
assertEquals(se.getFileName(), "myfile.js");
|
||||||
// se.printStackTrace();
|
// se.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +252,7 @@ public class ScriptEngineTest {
|
|||||||
fail(se.getMessage());
|
fail(se.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(Boolean.TRUE, res);
|
assertEquals(res, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -289,7 +290,7 @@ public class ScriptEngineTest {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
e.eval("var x = 'hello'");
|
e.eval("var x = 'hello'");
|
||||||
assertEquals("hello", e.get("x"));
|
assertEquals(e.get("x"), "hello");
|
||||||
} catch (final ScriptException exp) {
|
} catch (final ScriptException exp) {
|
||||||
exp.printStackTrace();
|
exp.printStackTrace();
|
||||||
fail(exp.getMessage());
|
fail(exp.getMessage());
|
||||||
@ -310,21 +311,21 @@ public class ScriptEngineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void alert(final Object self, final Object msg) {
|
public static void alert(final Object msg) {
|
||||||
System.out.println(msg);
|
System.out.println(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void exposeFunctionTest() {
|
public void exposeMethodTest() {
|
||||||
final ScriptEngineManager m = new ScriptEngineManager();
|
final ScriptEngineManager m = new ScriptEngineManager();
|
||||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final Method alert = ScriptEngineTest.class.getMethod("alert", Object.class, Object.class);
|
final Method alert = ScriptEngineTest.class.getMethod("alert", Object.class);
|
||||||
// expose a Method object as global var.
|
// expose a Method object as global var.
|
||||||
e.put("alert", alert);
|
e.put("alert", alert);
|
||||||
// call the global var.
|
// call the global var.
|
||||||
e.eval("alert('alert! alert!!')");
|
e.eval("alert.invoke(null, 'alert! alert!!')");
|
||||||
} catch (final NoSuchMethodException | SecurityException | ScriptException exp) {
|
} catch (final NoSuchMethodException | SecurityException | ScriptException exp) {
|
||||||
exp.printStackTrace();
|
exp.printStackTrace();
|
||||||
fail(exp.getMessage());
|
fail(exp.getMessage());
|
||||||
@ -359,11 +360,8 @@ public class ScriptEngineTest {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
e.put("window", window);
|
e.put("window", window);
|
||||||
e.eval("print(window.alert)"); // TODO: bug - prints 'undefined'
|
e.eval("print(window.alert)");
|
||||||
e.eval("window.alert('calling window.alert...')");
|
e.eval("window.alert('calling window.alert...')");
|
||||||
// TODO: java.lang.NoSuchMethodException: alert
|
|
||||||
// ((Invocable) e).invokeMethod(window, "alert",
|
|
||||||
// "invoking window.alert...");
|
|
||||||
} catch (final Exception exp) {
|
} catch (final Exception exp) {
|
||||||
exp.printStackTrace();
|
exp.printStackTrace();
|
||||||
fail(exp.getMessage());
|
fail(exp.getMessage());
|
||||||
@ -379,8 +377,8 @@ public class ScriptEngineTest {
|
|||||||
try {
|
try {
|
||||||
e.put("window", window);
|
e.put("window", window);
|
||||||
e.eval("print(window.location)");
|
e.eval("print(window.location)");
|
||||||
final Object locationValue = ((Invocable)e).invokeMethod(window, "getLocation");
|
final Object locationValue = e.eval("window.getLocation()");
|
||||||
assertEquals("http://localhost:8080/window", locationValue);
|
assertEquals(locationValue, "http://localhost:8080/window");
|
||||||
} catch (final Exception exp) {
|
} catch (final Exception exp) {
|
||||||
exp.printStackTrace();
|
exp.printStackTrace();
|
||||||
fail(exp.getMessage());
|
fail(exp.getMessage());
|
||||||
@ -396,9 +394,9 @@ public class ScriptEngineTest {
|
|||||||
try {
|
try {
|
||||||
e.put("window", window);
|
e.put("window", window);
|
||||||
final String item1 = (String)e.eval("window.item(65535)");
|
final String item1 = (String)e.eval("window.item(65535)");
|
||||||
assertEquals("ffff", item1);
|
assertEquals(item1, "ffff");
|
||||||
final String item2 = (String)((Invocable)e).invokeMethod(window, "item", 255);
|
final String item2 = (String)e.eval("window.item(255)");
|
||||||
assertEquals("ff", item2);
|
assertEquals(item2, "ff");
|
||||||
} catch (final Exception exp) {
|
} catch (final Exception exp) {
|
||||||
exp.printStackTrace();
|
exp.printStackTrace();
|
||||||
fail(exp.getMessage());
|
fail(exp.getMessage());
|
||||||
@ -434,9 +432,9 @@ public class ScriptEngineTest {
|
|||||||
e.eval("throw 'foo'");
|
e.eval("throw 'foo'");
|
||||||
} catch (final ScriptException exp) {
|
} catch (final ScriptException exp) {
|
||||||
log(exp.getMessage());
|
log(exp.getMessage());
|
||||||
assertEquals("foo in throwtest.js at line number 1 at column number 0", exp.getMessage());
|
assertEquals(exp.getMessage(), "foo in throwtest.js at line number 1 at column number 0");
|
||||||
assertEquals("throwtest.js", exp.getFileName());
|
assertEquals(exp.getFileName(), "throwtest.js");
|
||||||
assertEquals(1, exp.getLineNumber());
|
assertEquals(exp.getLineNumber(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,18 +489,18 @@ public class ScriptEngineTest {
|
|||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
Map<Object, Object> map = (Map<Object, Object>)e.get("obj");
|
Map<Object, Object> map = (Map<Object, Object>)e.get("obj");
|
||||||
assertEquals(false, map.isEmpty());
|
assertFalse(map.isEmpty());
|
||||||
assertEquals(true, map.keySet().contains("x"));
|
assertTrue(map.keySet().contains("x"));
|
||||||
assertEquals(true, map.containsKey("x"));
|
assertTrue(map.containsKey("x"));
|
||||||
assertEquals(true, map.values().contains("nashorn"));
|
assertTrue(map.values().contains("nashorn"));
|
||||||
assertEquals(true, map.containsValue("nashorn"));
|
assertTrue(map.containsValue("nashorn"));
|
||||||
for (final Map.Entry<?, ?> ex : map.entrySet()) {
|
for (final Map.Entry<?, ?> ex : map.entrySet()) {
|
||||||
final Object key = ex.getKey();
|
final Object key = ex.getKey();
|
||||||
if (key.equals("x")) {
|
if (key.equals("x")) {
|
||||||
assertTrue(344 == ((Number)ex.getValue()).doubleValue());
|
assertTrue(344 == ((Number)ex.getValue()).doubleValue());
|
||||||
count++;
|
count++;
|
||||||
} else if (key.equals("y")) {
|
} else if (key.equals("y")) {
|
||||||
assertEquals("nashorn", ex.getValue());
|
assertEquals(ex.getValue(), "nashorn");
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -511,56 +509,56 @@ public class ScriptEngineTest {
|
|||||||
|
|
||||||
// add property
|
// add property
|
||||||
map.put("z", "hello");
|
map.put("z", "hello");
|
||||||
assertEquals("hello", e.eval("obj.z"));
|
assertEquals(e.eval("obj.z"), "hello");
|
||||||
assertEquals("hello", map.get("z"));
|
assertEquals(map.get("z"), "hello");
|
||||||
assertEquals(true, map.keySet().contains("z"));
|
assertTrue(map.keySet().contains("z"));
|
||||||
assertEquals(true, map.containsKey("z"));
|
assertTrue(map.containsKey("z"));
|
||||||
assertEquals(true, map.values().contains("hello"));
|
assertTrue(map.values().contains("hello"));
|
||||||
assertEquals(true, map.containsValue("hello"));
|
assertTrue(map.containsValue("hello"));
|
||||||
assertEquals(3, map.size());
|
assertEquals(map.size(), 3);
|
||||||
|
|
||||||
final Map<Object, Object> newMap = new HashMap<>();
|
final Map<Object, Object> newMap = new HashMap<>();
|
||||||
newMap.put("foo", 23.0);
|
newMap.put("foo", 23.0);
|
||||||
newMap.put("bar", true);
|
newMap.put("bar", true);
|
||||||
map.putAll(newMap);
|
map.putAll(newMap);
|
||||||
|
|
||||||
assertEquals(23.0, e.eval("obj.foo"));
|
assertEquals(e.eval("obj.foo"), 23.0);
|
||||||
assertEquals(true, e.eval("obj.bar"));
|
assertEquals(e.eval("obj.bar"), true);
|
||||||
|
|
||||||
// remove using map method
|
// remove using map method
|
||||||
map.remove("foo");
|
map.remove("foo");
|
||||||
assertEquals("undefined", e.eval("typeof obj.foo"));
|
assertEquals(e.eval("typeof obj.foo"), "undefined");
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
e.eval("var arr = [ true, 'hello' ]");
|
e.eval("var arr = [ true, 'hello' ]");
|
||||||
map = (Map<Object, Object>)e.get("arr");
|
map = (Map<Object, Object>)e.get("arr");
|
||||||
assertEquals(false, map.isEmpty());
|
assertFalse(map.isEmpty());
|
||||||
assertEquals(true, map.containsKey("length"));
|
assertTrue(map.containsKey("length"));
|
||||||
assertEquals(true, map.containsValue("hello"));
|
assertTrue(map.containsValue("hello"));
|
||||||
for (final Map.Entry<?, ?> ex : map.entrySet()) {
|
for (final Map.Entry<?, ?> ex : map.entrySet()) {
|
||||||
final Object key = ex.getKey();
|
final Object key = ex.getKey();
|
||||||
if (key.equals("0")) {
|
if (key.equals("0")) {
|
||||||
assertEquals(Boolean.TRUE, ex.getValue());
|
assertEquals(ex.getValue(), Boolean.TRUE);
|
||||||
count++;
|
count++;
|
||||||
} else if (key.equals("1")) {
|
} else if (key.equals("1")) {
|
||||||
assertEquals("hello", ex.getValue());
|
assertEquals(ex.getValue(), "hello");
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertEquals(2, count);
|
assertEquals(count, 2);
|
||||||
assertEquals(2, map.size());
|
assertEquals(map.size(), 2);
|
||||||
|
|
||||||
// add element
|
// add element
|
||||||
map.put(2, "world");
|
map.put("2", "world");
|
||||||
assertEquals("world", map.get(2));
|
assertEquals(map.get("2"), "world");
|
||||||
assertEquals(3, map.size());
|
assertEquals(map.size(), 3);
|
||||||
|
|
||||||
// remove all
|
// remove all
|
||||||
map.clear();
|
map.clear();
|
||||||
assertEquals(true, map.isEmpty());
|
assertTrue(map.isEmpty());
|
||||||
assertEquals("undefined", e.eval("typeof arr[0]"));
|
assertEquals(e.eval("typeof arr[0]"), "undefined");
|
||||||
assertEquals("undefined", e.eval("typeof arr[1]"));
|
assertEquals(e.eval("typeof arr[1]"), "undefined");
|
||||||
assertEquals("undefined", e.eval("typeof arr[2]"));
|
assertEquals(e.eval("typeof arr[2]"), "undefined");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -585,7 +583,7 @@ public class ScriptEngineTest {
|
|||||||
e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();");
|
e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();");
|
||||||
final Object obj = e.get("myExample");
|
final Object obj = e.get("myExample");
|
||||||
final Object res = ((Invocable)e).invokeMethod(obj, "hello");
|
final Object res = ((Invocable)e).invokeMethod(obj, "hello");
|
||||||
assertEquals("Hello World!", res);
|
assertEquals(res, "Hello World!");
|
||||||
} catch (final Exception exp) {
|
} catch (final Exception exp) {
|
||||||
exp.printStackTrace();
|
exp.printStackTrace();
|
||||||
fail(exp.getMessage());
|
fail(exp.getMessage());
|
||||||
@ -867,7 +865,7 @@ public class ScriptEngineTest {
|
|||||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||||
try {
|
try {
|
||||||
Object obj = e.eval("new TypeError('wrong type')");
|
Object obj = e.eval("new TypeError('wrong type')");
|
||||||
Assert.assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value");
|
assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value");
|
||||||
} catch (final Throwable t) {
|
} catch (final Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
fail(t.getMessage());
|
fail(t.getMessage());
|
||||||
@ -875,10 +873,53 @@ public class ScriptEngineTest {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Object obj = e.eval("function func() { print('hello'); }");
|
Object obj = e.eval("function func() { print('hello'); }");
|
||||||
Assert.assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value");
|
assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value");
|
||||||
} catch (final Throwable t) {
|
} catch (final Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
fail(t.getMessage());
|
fail(t.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void engineScopeTest() {
|
||||||
|
final ScriptEngineManager m = new ScriptEngineManager();
|
||||||
|
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||||
|
Bindings engineScope = e.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||||
|
|
||||||
|
// check few ECMA standard built-in global properties
|
||||||
|
assertNotNull(engineScope.get("Object"));
|
||||||
|
assertNotNull(engineScope.get("TypeError"));
|
||||||
|
assertNotNull(engineScope.get("eval"));
|
||||||
|
|
||||||
|
// can access via ScriptEngine.get as well
|
||||||
|
assertNotNull(e.get("Object"));
|
||||||
|
assertNotNull(e.get("TypeError"));
|
||||||
|
assertNotNull(e.get("eval"));
|
||||||
|
|
||||||
|
// Access by either way should return same object
|
||||||
|
assertEquals(engineScope.get("Array"), e.get("Array"));
|
||||||
|
assertEquals(engineScope.get("EvalError"), e.get("EvalError"));
|
||||||
|
assertEquals(engineScope.get("undefined"), e.get("undefined"));
|
||||||
|
|
||||||
|
// try exposing a new variable from scope
|
||||||
|
engineScope.put("myVar", "foo");
|
||||||
|
try {
|
||||||
|
assertEquals(e.eval("myVar"), "foo");
|
||||||
|
} catch (final ScriptException se) {
|
||||||
|
se.printStackTrace();
|
||||||
|
fail(se.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// update "myVar" in script an check the value from scope
|
||||||
|
try {
|
||||||
|
e.eval("myVar = 'nashorn';");
|
||||||
|
} catch (final ScriptException se) {
|
||||||
|
se.printStackTrace();
|
||||||
|
fail(se.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check modified value from scope and engine
|
||||||
|
assertEquals(engineScope.get("myVar"), "nashorn");
|
||||||
|
assertEquals(e.get("myVar"), "nashorn");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user