--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Fri Aug 23 12:44:01 2013 +0200
@@ -55,6 +55,7 @@
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
+import javax.script.SimpleBindings;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.GlobalObject;
@@ -74,6 +75,12 @@
*/
public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable {
+ /**
+ * Key used to associate Nashorn global object mirror with arbitrary Bindings instance.
+ */
+ public static final String NASHORN_GLOBAL = "nashorn.global";
+
+ // commonly used access control context objects
private static AccessControlContext createPermAccCtxt(final String permName) {
final Permissions perms = new Permissions();
perms.add(new RuntimePermission(permName));
@@ -83,16 +90,23 @@
private static final AccessControlContext CREATE_CONTEXT_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_CONTEXT);
private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_GLOBAL);
+ // the factory that created this engine
private final ScriptEngineFactory factory;
+ // underlying nashorn Context - 1:1 with engine instance
private final Context nashornContext;
+ // do we want to share single Nashorn global instance across ENGINE_SCOPEs?
+ private final boolean _global_per_engine;
+ // This is the initial default Nashorn global object.
+ // This is used as "shared" global if above option is true.
private final ScriptObject global;
- // initialized bit late to be made 'final'. Property object for "context"
- // property of global object
- private Property contextProperty;
+ // initialized bit late to be made 'final'.
+ // Property object for "context" property of global object.
+ private volatile Property contextProperty;
// default options passed to Nashorn Options object
private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-doe" };
+ // Nashorn script engine error message management
private static final String MESSAGES_RESOURCE = "jdk.nashorn.api.scripting.resources.Messages";
private static final ResourceBundle MESSAGES_BUNDLE;
@@ -100,6 +114,7 @@
MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault());
}
+ // helper to get Nashorn script engine error message
private static String getMessage(final String msgId, final String... args) {
try {
return new MessageFormat(MESSAGES_BUNDLE.getString(msgId)).format(args);
@@ -108,6 +123,30 @@
}
}
+ // load engine.js and return content as a char[]
+ private static char[] loadEngineJSSource() {
+ final String script = "resources/engine.js";
+ try {
+ final InputStream is = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<InputStream>() {
+ @Override
+ public InputStream run() throws Exception {
+ final URL url = NashornScriptEngine.class.getResource(script);
+ return url.openStream();
+ }
+ });
+ return Source.readFully(new InputStreamReader(is));
+ } catch (final PrivilegedActionException | IOException e) {
+ if (Context.DEBUG) {
+ e.printStackTrace();
+ }
+ throw new RuntimeException(e);
+ }
+ }
+
+ // Source object for engine.js
+ private static final Source ENGINE_SCRIPT_SRC = new Source(NashornException.ENGINE_SCRIPT_SOURCE_NAME, loadEngineJSSource());
+
NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) {
this(factory, DEFAULT_OPTIONS, appLoader);
}
@@ -134,20 +173,13 @@
}
}, CREATE_CONTEXT_ACC_CTXT);
- // create new global object
- this.global = createNashornGlobal();
- // set the default engine scope for the default context
- context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
+ // cache this option that is used often
+ this._global_per_engine = nashornContext.getEnv()._global_per_engine;
- // evaluate engine initial script
- try {
- evalEngineScript();
- } catch (final ScriptException e) {
- if (Context.DEBUG) {
- e.printStackTrace();
- }
- throw new RuntimeException(e);
- }
+ // create new global object
+ this.global = createNashornGlobal(context);
+ // set the default ENGINE_SCOPE object for the default context
+ context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
}
@Override
@@ -176,8 +208,13 @@
@Override
public Bindings createBindings() {
- final ScriptObject newGlobal = createNashornGlobal();
- return new ScriptObjectMirror(newGlobal, newGlobal);
+ if (_global_per_engine) {
+ // just create normal SimpleBindings.
+ // We use same 'global' for all Bindings.
+ return new SimpleBindings();
+ } else {
+ return createGlobalMirror(null);
+ }
}
// Compilable methods
@@ -213,6 +250,48 @@
return invokeImpl(thiz, name, args);
}
+ @Override
+ public <T> T getInterface(final Class<T> clazz) {
+ return getInterfaceInner(null, clazz);
+ }
+
+ @Override
+ public <T> T getInterface(final Object thiz, final Class<T> clazz) {
+ if (thiz == null) {
+ throw new IllegalArgumentException(getMessage("thiz.cannot.be.null"));
+ }
+ return getInterfaceInner(thiz, clazz);
+ }
+
+ // These are called from the "engine.js" script
+
+ /**
+ * This hook is used to search js global variables exposed from Java code.
+ *
+ * @param self 'this' passed from the script
+ * @param ctxt current ScriptContext in which name is searched
+ * @param name name of the variable searched
+ * @return the value of the named variable
+ */
+ public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) {
+ if (ctxt != null) {
+ final int scope = ctxt.getAttributesScope(name);
+ final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
+ if (scope != -1) {
+ return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal);
+ }
+
+ if (self == UNDEFINED) {
+ // scope access and so throw ReferenceError
+ throw referenceError(ctxtGlobal, "not.defined", name);
+ }
+ }
+
+ return UNDEFINED;
+ }
+
+ // Implementation only below this point
+
private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) {
if (clazz == null || !clazz.isInterface()) {
throw new IllegalArgumentException(getMessage("interface.class.expected"));
@@ -280,58 +359,56 @@
}
}
- @Override
- public <T> T getInterface(final Class<T> clazz) {
- return getInterfaceInner(null, clazz);
- }
+ // Retrieve nashorn Global object for a given ScriptContext object
+ private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) {
+ if (_global_per_engine) {
+ // shared single global object for all ENGINE_SCOPE Bindings
+ return global;
+ }
- @Override
- public <T> T getInterface(final Object thiz, final Class<T> clazz) {
- if (thiz == null) {
- throw new IllegalArgumentException(getMessage("thiz.cannot.be.null"));
+ final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE);
+ // is this Nashorn's own Bindings implementation?
+ if (bindings instanceof ScriptObjectMirror) {
+ final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)bindings);
+ if (sobj != null) {
+ return sobj;
+ }
}
- return getInterfaceInner(thiz, clazz);
+
+ // Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it!
+ Object scope = bindings.get(NASHORN_GLOBAL);
+ if (scope instanceof ScriptObjectMirror) {
+ final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)scope);
+ if (sobj != null) {
+ return sobj;
+ }
+ }
+
+ // We didn't find associated nashorn global mirror in the Bindings given!
+ // Create new global instance mirror and associate with the Bindings.
+ final ScriptObjectMirror mirror = createGlobalMirror(ctxt);
+ bindings.put(NASHORN_GLOBAL, mirror);
+ return mirror.getScriptObject();
}
- // These are called from the "engine.js" script
-
- /**
- * This hook is used to search js global variables exposed from Java code.
- *
- * @param self 'this' passed from the script
- * @param ctxt current ScriptContext in which name is searched
- * @param name name of the variable searched
- * @return the value of the named variable
- */
- public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) {
- final int scope = ctxt.getAttributesScope(name);
- final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
- if (scope != -1) {
- return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal);
+ // Retrieve nashorn Global object from a given ScriptObjectMirror
+ private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) {
+ ScriptObject sobj = mirror.getScriptObject();
+ if (sobj instanceof GlobalObject && sobj.isOfContext(nashornContext)) {
+ return sobj;
}
- if (self == UNDEFINED) {
- // scope access and so throw ReferenceError
- throw referenceError(ctxtGlobal, "not.defined", name);
- }
-
- return UNDEFINED;
+ return null;
}
- private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) {
- final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE);
- if (bindings instanceof ScriptObjectMirror) {
- ScriptObject sobj = ((ScriptObjectMirror)bindings).getScriptObject();
- if (sobj instanceof GlobalObject) {
- return sobj;
- }
- }
-
- // didn't find global object from context given - return the engine-wide global
- return global;
+ // Create a new ScriptObjectMirror wrapping a newly created Nashorn Global object
+ private ScriptObjectMirror createGlobalMirror(final ScriptContext ctxt) {
+ final ScriptObject newGlobal = createNashornGlobal(ctxt);
+ return new ScriptObjectMirror(newGlobal, newGlobal);
}
- private ScriptObject createNashornGlobal() {
+ // Create a new Nashorn Global object
+ private ScriptObject createNashornGlobal(final ScriptContext ctxt) {
final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction<ScriptObject>() {
@Override
public ScriptObject run() {
@@ -352,7 +429,7 @@
// current ScriptContext exposed as "context"
// "context" is non-writable from script - but script engine still
// needs to set it and so save the context Property object
- contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, UNDEFINED);
+ contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, null);
// current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as
// NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property
// in the Global of a Context we just created - both the Context and the Global were just created and can not be
@@ -362,38 +439,17 @@
newGlobal.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED);
// file name default is null
newGlobal.addOwnProperty(ScriptEngine.FILENAME, Property.NOT_ENUMERABLE, null);
+ // evaluate engine.js initialization script this new global object
+ try {
+ evalImpl(compileImpl(ENGINE_SCRIPT_SRC, newGlobal), ctxt, newGlobal);
+ } catch (final ScriptException exp) {
+ throw new RuntimeException(exp);
+ }
return newGlobal;
}
- private void evalEngineScript() throws ScriptException {
- final String script = "resources/engine.js";
- final String name = NashornException.ENGINE_SCRIPT_SOURCE_NAME;
- try {
- final InputStream is = AccessController.doPrivileged(
- new PrivilegedExceptionAction<InputStream>() {
- @Override
- public InputStream run() throws Exception {
- final URL url = NashornScriptEngine.class.getResource(script);
- return url.openStream();
- }
- });
- put(ScriptEngine.FILENAME, name);
- try (final InputStreamReader isr = new InputStreamReader(is)) {
- eval(isr);
- }
- } catch (final PrivilegedActionException | IOException e) {
- if (Context.DEBUG) {
- e.printStackTrace();
- }
- throw new ScriptException(e);
- } finally {
- put(ScriptEngine.FILENAME, null);
- }
- }
-
- // scripts should see "context" and "engine" as variables
- private void setContextVariables(final ScriptContext ctxt) {
- final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
+ // scripts should see "context" and "engine" as variables in the given global object
+ private void setContextVariables(final ScriptObject ctxtGlobal, final ScriptContext ctxt) {
// set "context" global variable via contextProperty - because this
// property is non-writable
contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false);
@@ -402,8 +458,10 @@
args = ScriptRuntime.EMPTY_ARRAY;
}
// if no arguments passed, expose it
- args = ((GlobalObject)ctxtGlobal).wrapAsObject(args);
- ctxtGlobal.set("arguments", args, false);
+ if (! (args instanceof ScriptObject)) {
+ args = ((GlobalObject)ctxtGlobal).wrapAsObject(args);
+ ctxtGlobal.set("arguments", args, false);
+ }
}
private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
@@ -456,18 +514,24 @@
}
private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt) throws ScriptException {
+ return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt));
+ }
+
+ private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final ScriptObject ctxtGlobal) throws ScriptException {
if (script == null) {
return null;
}
final ScriptObject oldGlobal = Context.getGlobal();
- final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
final boolean globalChanged = (oldGlobal != ctxtGlobal);
try {
if (globalChanged) {
Context.setGlobal(ctxtGlobal);
}
- setContextVariables(ctxt);
+ // set ScriptContext variables if ctxt is non-null
+ if (ctxt != null) {
+ setContextVariables(ctxtGlobal, ctxt);
+ }
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
} catch (final Exception e) {
throwAsScriptException(e);
@@ -517,15 +581,18 @@
}
private ScriptFunction compileImpl(final Source source, final ScriptContext ctxt) throws ScriptException {
+ return compileImpl(source, getNashornGlobalFrom(ctxt));
+ }
+
+ private ScriptFunction compileImpl(final Source source, final ScriptObject newGlobal) throws ScriptException {
final ScriptObject oldGlobal = Context.getGlobal();
- final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
- final boolean globalChanged = (oldGlobal != ctxtGlobal);
+ final boolean globalChanged = (oldGlobal != newGlobal);
try {
if (globalChanged) {
- Context.setGlobal(ctxtGlobal);
+ Context.setGlobal(newGlobal);
}
- return nashornContext.compileScript(source, ctxtGlobal);
+ return nashornContext.compileScript(source, newGlobal);
} catch (final Exception e) {
throwAsScriptException(e);
throw new AssertionError("should not reach here");
--- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Fri Aug 23 12:44:01 2013 +0200
@@ -99,12 +99,14 @@
}
final Object val = functionName == null? sobj : sobj.get(functionName);
- if (! (val instanceof ScriptFunction)) {
- throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : ""));
+ if (val instanceof ScriptFunction) {
+ final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
+ return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
+ } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
+ return ((ScriptObjectMirror)val).call(null, args);
}
- final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
- return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
+ throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : ""));
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
@@ -127,12 +129,14 @@
}
final Object val = functionName == null? sobj : sobj.get(functionName);
- if (! (val instanceof ScriptFunction)) {
- throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : ""));
+ if (val instanceof ScriptFunction) {
+ final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
+ return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
+ } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
+ return ((ScriptObjectMirror)val).newObject(null, args);
}
- final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
- return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
+ throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : ""));
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
--- a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js Fri Aug 23 12:44:01 2013 +0200
@@ -23,10 +23,9 @@
/**
* This script file is executed by script engine at the construction
- * of the engine. The functions here assume global variables "context"
- * of type javax.script.ScriptContext and "engine" of the type
+ * of the every new Global object. The functions here assume global variables
+ * "context" of type javax.script.ScriptContext and "engine" of the type
* jdk.nashorn.api.scripting.NashornScriptEngine.
- *
**/
Object.defineProperty(this, "__noSuchProperty__", {
@@ -40,7 +39,7 @@
});
function print() {
- var writer = context.getWriter();
+ var writer = context != null? context.writer : engine.context.writer;
if (! (writer instanceof java.io.PrintWriter)) {
writer = new java.io.PrintWriter(writer);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java Fri Aug 23 12:44:01 2013 +0200
@@ -91,6 +91,11 @@
*/
public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection";
+ /* Force DebuggerSupport to be loaded. */
+ static {
+ DebuggerSupport.FORCELOAD = true;
+ }
+
/**
* ContextCodeInstaller that has the privilege of installing classes in the Context.
* Can only be instantiated from inside the context and is opaque to other classes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java Fri Aug 23 12:44:01 2013 +0200
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class provides support for external debuggers. Its primary purpose is
+ * is to simplify the debugger tasks and provide better performance.
+ */
+final class DebuggerSupport {
+ /**
+ * Hook to force the loading of the DebuggerSupport class so that it is
+ * available to external debuggers.
+ */
+ static boolean FORCELOAD = true;
+
+ static {
+ /**
+ * Hook to force the loading of the DebuggerValueDesc class so that it is
+ * available to external debuggers.
+ */
+ DebuggerValueDesc forceLoad = new DebuggerValueDesc(null, false, null, null);
+ }
+
+ /** This class is used to send a bulk description of a value. */
+ static class DebuggerValueDesc {
+ /** Property key (or index) or field name. */
+ final String key;
+
+ /** If the value is expandable. */
+ final boolean expandable;
+
+ /** Property or field value as object. */
+ final Object valueAsObject;
+
+ /** Property or field value as string. */
+ final String valueAsString;
+
+ DebuggerValueDesc(final String key, final boolean expandable, final Object valueAsObject, final String valueAsString) {
+ this.key = key;
+ this.expandable = expandable;
+ this.valueAsObject = valueAsObject;
+ this.valueAsString = valueAsString;
+ }
+ }
+
+ /**
+ * Return the current context global.
+ * @return context global.
+ */
+ static Object getGlobal() {
+ return Context.getGlobalTrusted();
+ }
+
+ /**
+ * This method returns a bulk description of an object's properties.
+ * @param object Script object to be displayed by the debugger.
+ * @param all true if to include non-enumerable values.
+ * @return An array of DebuggerValueDesc.
+ */
+ static DebuggerValueDesc[] valueInfos(final Object object, final boolean all) {
+ assert object instanceof ScriptObject;
+ return getDebuggerValueDescs((ScriptObject)object, all, new HashSet<>());
+ }
+
+ /**
+ * This method returns a debugger description of the value.
+ * @param name Name of value (property name).
+ * @param value Data value.
+ * @param all true if to include non-enumerable values.
+ * @return A DebuggerValueDesc.
+ */
+ static DebuggerValueDesc valueInfo(final String name, final Object value, final boolean all) {
+ return valueInfo(name, value, all, new HashSet<>());
+ }
+
+ /**
+ * This method returns a debugger description of the value.
+ * @param name Name of value (property name).
+ * @param value Data value.
+ * @param all true if to include non-enumerable values.
+ * @param duplicates Duplication set to avoid cycles.
+ * @return A DebuggerValueDesc.
+ */
+ private static DebuggerValueDesc valueInfo(final String name, final Object value, final boolean all, final Set<Object> duplicates) {
+ if (value instanceof ScriptObject && !(value instanceof ScriptFunction)) {
+ final ScriptObject object = (ScriptObject)value;
+ return new DebuggerValueDesc(name, !object.isEmpty(), value, objectAsString(object, all, duplicates));
+ } else {
+ return new DebuggerValueDesc(name, false, value, valueAsString(value));
+ }
+ }
+
+ /**
+ * Generate the descriptions for an object's properties.
+ * @param object Object to introspect.
+ * @param all true if to include non-enumerable values.
+ * @param duplicates Duplication set to avoid cycles.
+ * @return An array of DebuggerValueDesc.
+ */
+ private static DebuggerValueDesc[] getDebuggerValueDescs(final ScriptObject object, final boolean all, final Set<Object> duplicates) {
+ if (duplicates.contains(object)) {
+ return null;
+ }
+
+ duplicates.add(object);
+
+ final String[] keys = object.getOwnKeys(all);
+ final DebuggerValueDesc[] descs = new DebuggerValueDesc[keys.length];
+
+ for (int i = 0; i < keys.length; i++) {
+ final String key = keys[i];
+ descs[i] = valueInfo(key, object.get(key), true, duplicates);
+ }
+
+ duplicates.remove(object);
+
+ return descs;
+ }
+
+ /**
+ * Generate a string representation of a Script object.
+ * @param object Script object to represent.
+ * @param all true if to include non-enumerable values.
+ * @param duplicates Duplication set to avoid cycles.
+ * @return String representation.
+ */
+ private static String objectAsString(final ScriptObject object, final boolean all, final Set<Object> duplicates) {
+ final StringBuilder sb = new StringBuilder();
+
+ if (ScriptObject.isArray(object)) {
+ sb.append('[');
+ final long length = object.getLong("length");
+
+ for (long i = 0; i < length; i++) {
+ if (object.has(i)) {
+ final Object valueAsObject = object.get(i);
+ final boolean isUndefined = JSType.of(valueAsObject) == JSType.UNDEFINED;
+
+ if (isUndefined) {
+ if (i != 0) {
+ sb.append(",");
+ }
+ } else {
+ if (i != 0) {
+ sb.append(", ");
+ }
+
+ if (valueAsObject instanceof ScriptObject && !(valueAsObject instanceof ScriptFunction)) {
+ final String objectString = objectAsString((ScriptObject)valueAsObject, true, duplicates);
+ sb.append(objectString != null ? objectString : "{...}");
+ } else {
+ sb.append(valueAsString(valueAsObject));
+ }
+ }
+ } else {
+ if (i != 0) {
+ sb.append(',');
+ }
+ }
+ }
+
+ sb.append(']');
+ } else {
+ sb.append('{');
+ final DebuggerValueDesc[] descs = getDebuggerValueDescs(object, all, duplicates);
+
+ if (descs != null) {
+ for (int i = 0; i < descs.length; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+
+ final String valueAsString = descs[i].valueAsString;
+ sb.append(descs[i].key);
+ sb.append(": ");
+ sb.append(descs[i].valueAsString);
+ }
+ }
+
+ sb.append('}');
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * This method returns a string representation of a value.
+ * @param value Arbitrary value to be displayed by the debugger.
+ * @return A string representation of the value or an array of DebuggerValueDesc.
+ */
+ private static String valueAsString(final Object value) {
+ final JSType type = JSType.of(value);
+
+ switch (type) {
+ case BOOLEAN:
+ return value.toString();
+
+ case STRING:
+ return escape((String)value);
+
+ case NUMBER:
+ return JSType.toString(((Number)value).doubleValue());
+
+ case NULL:
+ return "null";
+
+ case UNDEFINED:
+ return "undefined";
+
+ case OBJECT:
+ return ScriptRuntime.safeToString(value);
+
+ case FUNCTION:
+ if (value instanceof ScriptFunction) {
+ return ((ScriptFunction)value).toSource();
+ } else {
+ return value.toString();
+ }
+
+ default:
+ return value.toString();
+ }
+ }
+
+ /**
+ * Escape a string into a form that can be parsed by JavaScript.
+ * @param value String to be escaped.
+ * @return Escaped string.
+ */
+ private static String escape(final String value) {
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append("\"");
+
+ for (final char ch : value.toCharArray()) {
+ switch (ch) {
+ case '\\':
+ sb.append("\\\\");
+ break;
+ case '"':
+ sb.append("\\\"");
+ break;
+ case '\'':
+ sb.append("\\\'");
+ break;
+ case '\b':
+ sb.append("\\b");
+ break;
+ case '\f':
+ sb.append("\\f");
+ break;
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ default:
+ if (ch < ' ' || ch >= 0xFF) {
+ sb.append("\\u");
+
+ final String hex = Integer.toHexString(ch);
+ for (int i = hex.length(); i < 4; i++) {
+ sb.append('0');
+ }
+ sb.append(hex);
+ } else {
+ sb.append(ch);
+ }
+
+ break;
+ }
+ }
+
+ sb.append("\"");
+
+ return sb.toString();
+ }
+}
+
+
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri Aug 23 12:44:01 2013 +0200
@@ -86,6 +86,9 @@
/** Launch using as fx application */
public final boolean _fx;
+ /** Use single Global instance per jsr223 engine instance. */
+ public final boolean _global_per_engine;
+
/**
* Behavior when encountering a function declaration in a lexical context where only statements are acceptable
* (function declarations are source elements, but not statements).
@@ -208,6 +211,7 @@
_function_statement = FunctionStatementBehavior.ACCEPT;
}
_fx = options.getBoolean("fx");
+ _global_per_engine = options.getBoolean("global.per.engine");
_lazy_compilation = options.getBoolean("lazy.compilation");
_loader_per_compile = options.getBoolean("loader.per.compile");
_no_java = options.getBoolean("no.java");
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri Aug 23 12:44:01 2013 +0200
@@ -1008,10 +1008,6 @@
return getMap().findProperty(key);
}
- static String convertKey(final Object key) {
- return (key instanceof String) ? (String)key : JSType.toString(key);
- }
-
/**
* Overridden by {@link jdk.nashorn.internal.objects.NativeArguments} class (internal use.)
* Used for argument access in a vararg function using parameter name.
@@ -2374,7 +2370,7 @@
return array.getInt(index);
}
- return getInt(index, convertKey(key));
+ return getInt(index, JSType.toString(key));
}
@Override
@@ -2386,7 +2382,7 @@
return array.getInt(index);
}
- return getInt(index, convertKey(key));
+ return getInt(index, JSType.toString(key));
}
@Override
@@ -2398,7 +2394,7 @@
return array.getInt(index);
}
- return getInt(index, convertKey(key));
+ return getInt(index, JSType.toString(key));
}
@Override
@@ -2409,7 +2405,7 @@
return array.getInt(key);
}
- return getInt(key, convertKey(key));
+ return getInt(key, JSType.toString(key));
}
private long getLong(final int index, final String key) {
@@ -2451,7 +2447,7 @@
return array.getLong(index);
}
- return getLong(index, convertKey(key));
+ return getLong(index, JSType.toString(key));
}
@Override
@@ -2463,7 +2459,7 @@
return array.getLong(index);
}
- return getLong(index, convertKey(key));
+ return getLong(index, JSType.toString(key));
}
@Override
@@ -2475,7 +2471,7 @@
return array.getLong(index);
}
- return getLong(index, convertKey(key));
+ return getLong(index, JSType.toString(key));
}
@Override
@@ -2486,7 +2482,7 @@
return array.getLong(key);
}
- return getLong(key, convertKey(key));
+ return getLong(key, JSType.toString(key));
}
private double getDouble(final int index, final String key) {
@@ -2528,7 +2524,7 @@
return array.getDouble(index);
}
- return getDouble(index, convertKey(key));
+ return getDouble(index, JSType.toString(key));
}
@Override
@@ -2540,7 +2536,7 @@
return array.getDouble(index);
}
- return getDouble(index, convertKey(key));
+ return getDouble(index, JSType.toString(key));
}
@Override
@@ -2552,7 +2548,7 @@
return array.getDouble(index);
}
- return getDouble(index, convertKey(key));
+ return getDouble(index, JSType.toString(key));
}
@Override
@@ -2563,7 +2559,7 @@
return array.getDouble(key);
}
- return getDouble(key, convertKey(key));
+ return getDouble(key, JSType.toString(key));
}
private Object get(final int index, final String key) {
@@ -2605,7 +2601,7 @@
return array.getObject(index);
}
- return get(index, convertKey(key));
+ return get(index, JSType.toString(key));
}
@Override
@@ -2617,7 +2613,7 @@
return array.getObject(index);
}
- return get(index, convertKey(key));
+ return get(index, JSType.toString(key));
}
@Override
@@ -2629,7 +2625,7 @@
return array.getObject(index);
}
- return get(index, convertKey(key));
+ return get(index, JSType.toString(key));
}
@Override
@@ -2640,7 +2636,7 @@
return array.getObject(key);
}
- return get(key, convertKey(key));
+ return get(key, JSType.toString(key));
}
/**
@@ -2655,7 +2651,7 @@
final long longIndex = index & JSType.MAX_UINT;
if (!getArray().has(index)) {
- final String key = convertKey(longIndex);
+ final String key = JSType.toString(longIndex);
final FindProperty find = findProperty(key, true);
if (find != null) {
@@ -2801,7 +2797,7 @@
return;
}
- final String propName = convertKey(key);
+ final String propName = JSType.toString(key);
final FindProperty find = findProperty(propName, true);
setObject(find, strict, propName, value);
@@ -3023,7 +3019,7 @@
}
}
- final FindProperty find = findProperty(convertKey(key), true);
+ final FindProperty find = findProperty(JSType.toString(key), true);
return find != null;
}
@@ -3040,7 +3036,7 @@
}
}
- final FindProperty find = findProperty(convertKey(key), true);
+ final FindProperty find = findProperty(JSType.toString(key), true);
return find != null;
}
@@ -3057,7 +3053,7 @@
}
}
- final FindProperty find = findProperty(convertKey(key), true);
+ final FindProperty find = findProperty(JSType.toString(key), true);
return find != null;
}
@@ -3074,7 +3070,7 @@
}
}
- final FindProperty find = findProperty(convertKey(key), true);
+ final FindProperty find = findProperty(JSType.toString(key), true);
return find != null;
}
@@ -3087,7 +3083,7 @@
return true;
}
- final FindProperty find = findProperty(convertKey(key), false);
+ final FindProperty find = findProperty(JSType.toString(key), false);
return find != null;
}
@@ -3100,7 +3096,7 @@
return true;
}
- final FindProperty find = findProperty(convertKey(key), false);
+ final FindProperty find = findProperty(JSType.toString(key), false);
return find != null;
}
@@ -3113,7 +3109,7 @@
return true;
}
- final FindProperty find = findProperty(convertKey(key), false);
+ final FindProperty find = findProperty(JSType.toString(key), false);
return find != null;
}
@@ -3126,7 +3122,7 @@
return true;
}
- final FindProperty find = findProperty(convertKey(key), false);
+ final FindProperty find = findProperty(JSType.toString(key), false);
return find != null;
}
@@ -3196,7 +3192,7 @@
}
private boolean deleteObject(final Object key, final boolean strict) {
- final String propName = convertKey(key);
+ final String propName = JSType.toString(key);
final FindProperty find = findProperty(propName, false);
if (find == null) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java Fri Aug 23 12:44:01 2013 +0200
@@ -73,7 +73,7 @@
public boolean delete(final Object key, final boolean strict) {
if (expression instanceof ScriptObject) {
final ScriptObject self = (ScriptObject)expression;
- final String propName = ScriptObject.convertKey(key);
+ final String propName = JSType.toString(key);
final FindProperty find = self.findProperty(propName, true);
--- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExp.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExp.java Fri Aug 23 12:44:01 2013 +0200
@@ -60,7 +60,7 @@
* @param flags the flags string
*/
protected RegExp(final String source, final String flags) {
- this.source = source;
+ this.source = source.length() == 0 ? "(?:)" : source;
for (int i = 0; i < flags.length(); i++) {
final char ch = flags.charAt(i);
switch (ch) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Fri Aug 23 12:44:01 2013 +0200
@@ -157,6 +157,14 @@
default=false \
}
+nashorn.option.global.per.engine = { \
+ name="--global-per-engine", \
+ desc="Use single Global instance per script engine instance.", \
+ is_undocumented=true, \
+ type=Boolean, \
+ default=false \
+}
+
nashorn.option.log = { \
name="--log", \
is_undocumented=true, \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8023531.js Fri Aug 23 12:44:01 2013 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8023531: new RegExp('').toString() should return '/(?:)/'
+ *
+ * @test
+ * @run
+ */
+
+if (new RegExp("").toString() !== "/(?:)/") {
+ throw new Error();
+} else if (!(new RegExp("").test(""))) {
+ throw new Error();
+}
+
+if (new RegExp("", "g").toString() !== "/(?:)/g") {
+ throw new Error();
+} else if (!(new RegExp("", "g").test(""))) {
+ throw new Error();
+}
+
+if (new RegExp("", "i").toString() !== "/(?:)/i") {
+ throw new Error();
+} else if (!(new RegExp("", "i").test(""))) {
+ throw new Error();
+}
+
+if (new RegExp("", "m").toString() !== "/(?:)/m") {
+ throw new Error();
+} else if (!(new RegExp("", "m").test(""))) {
+ throw new Error();
+}
+
+if (RegExp("").toString() !== "/(?:)/") {
+ throw new Error();
+} else if (!RegExp("").test("")) {
+ throw new Error();
+}
+
+if (RegExp("", "g").toString() !== "/(?:)/g") {
+ throw new Error();
+} else if (!RegExp("", "g").test("")) {
+ throw new Error();
+}
+
+if (RegExp("", "i").toString() !== "/(?:)/i") {
+ throw new Error();
+} else if (!RegExp("", "i").test("")) {
+ throw new Error();
+}
+
+if (RegExp("", "m").toString() !== "/(?:)/m") {
+ throw new Error();
+} else if (!RegExp("", "m").test("")) {
+ throw new Error();
+}
+
+var re = /abc/;
+re.compile("");
+if (re.toString() !== "/(?:)/") {
+ throw new Error();
+} else if (!re.test("")) {
+ throw new Error();
+}
+
+re.compile("", "g");
+if (re.toString() !== "/(?:)/g") {
+ throw new Error();
+} else if (!re.test("")) {
+ throw new Error();
+}
+
+re.compile("", "i");
+if (re.toString() !== "/(?:)/i") {
+ throw new Error();
+} else if (!re.test("")) {
+ throw new Error();
+}
+
+re.compile("", "m");
+if (re.toString() !== "/(?:)/m") {
+ throw new Error();
+} else if (!re.test("")) {
+ throw new Error();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8023551.js Fri Aug 23 12:44:01 2013 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8023551: Mirror functions can not be invoked using invokeMethod, invokeFunction
+ *
+ * @test
+ * @run
+ */
+
+var m = new javax.script.ScriptEngineManager();
+var e = m.getEngineByName("nashorn");
+
+function func(x) {
+ print("func: " + x);
+}
+
+e.put("func", func);
+e.invokeFunction("func", "hello");
+
+var obj = e.eval("({ foo: func })");
+e.invokeMethod(obj, "foo", "world");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8023551.js.EXPECTED Fri Aug 23 12:44:01 2013 +0200
@@ -0,0 +1,2 @@
+func: hello
+func: world
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/InvocableTest.java Fri Aug 23 12:44:01 2013 +0200
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.api.scripting;
+
+import java.util.Objects;
+import javax.script.Invocable;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import javax.script.SimpleScriptContext;
+import org.testng.Assert;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+import org.testng.annotations.Test;
+
+/**
+ * Tests for javax.script.Invocable implementation of nashorn.
+ */
+public class InvocableTest {
+
+ private void log(String msg) {
+ org.testng.Reporter.log(msg, true);
+ }
+
+ @Test
+ public void invokeMethodTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();");
+ final Object obj = e.get("myExample");
+ final Object res = ((Invocable) e).invokeMethod(obj, "hello");
+ assertEquals(res, "Hello World!");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ @Test
+ /**
+ * Check that we can call invokeMethod on an object that we got by
+ * evaluating script with different Context set.
+ */
+ public void invokeMethodDifferentContextTest() {
+ ScriptEngineManager m = new ScriptEngineManager();
+ ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ // define an object with method on it
+ Object obj = e.eval("({ hello: function() { return 'Hello World!'; } })");
+
+ final ScriptContext ctxt = new SimpleScriptContext();
+ ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
+ e.setContext(ctxt);
+
+ // invoke 'func' on obj - but with current script context changed
+ final Object res = ((Invocable) e).invokeMethod(obj, "hello");
+ assertEquals(res, "Hello World!");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ @Test
+ /**
+ * Check that invokeMethod throws NPE on null method name.
+ */
+ public void invokeMethodNullNameTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ final Object obj = e.eval("({})");
+ final Object res = ((Invocable) e).invokeMethod(obj, null);
+ fail("should have thrown NPE");
+ } catch (final Exception exp) {
+ if (!(exp instanceof NullPointerException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that invokeMethod throws NoSuchMethodException on missing method.
+ */
+ public void invokeMethodMissingTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ final Object obj = e.eval("({})");
+ final Object res = ((Invocable) e).invokeMethod(obj, "nonExistentMethod");
+ fail("should have thrown NoSuchMethodException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof NoSuchMethodException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that calling method on non-script object 'thiz' results in
+ * IllegalArgumentException.
+ */
+ public void invokeMethodNonScriptObjectThizTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ ((Invocable) e).invokeMethod(new Object(), "toString");
+ fail("should have thrown IllegalArgumentException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof IllegalArgumentException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that calling method on null 'thiz' results in
+ * IllegalArgumentException.
+ */
+ public void invokeMethodNullThizTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ ((Invocable) e).invokeMethod(null, "toString");
+ fail("should have thrown IllegalArgumentException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof IllegalArgumentException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that calling method on mirror created by another engine results in
+ * IllegalArgumentException.
+ */
+ public void invokeMethodMixEnginesTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine engine1 = m.getEngineByName("nashorn");
+ final ScriptEngine engine2 = m.getEngineByName("nashorn");
+
+ try {
+ Object obj = engine1.eval("({ run: function() {} })");
+ // pass object from engine1 to engine2 as 'thiz' for invokeMethod
+ ((Invocable) engine2).invokeMethod(obj, "run");
+ fail("should have thrown IllegalArgumentException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof IllegalArgumentException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ public void getInterfaceTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Invocable inv = (Invocable) e;
+
+ // try to get interface from global functions
+ try {
+ e.eval("function run() { print('run'); };");
+ final Runnable runnable = inv.getInterface(Runnable.class);
+ runnable.run();
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+
+ // try interface on specific script object
+ try {
+ e.eval("var obj = { run: function() { print('run from obj'); } };");
+ Object obj = e.get("obj");
+ final Runnable runnable = inv.getInterface(obj, Runnable.class);
+ runnable.run();
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ public interface Foo {
+
+ public void bar();
+ }
+
+ public interface Foo2 extends Foo {
+
+ public void bar2();
+ }
+
+ @Test
+ public void getInterfaceMissingTest() {
+ final ScriptEngineManager manager = new ScriptEngineManager();
+ final ScriptEngine engine = manager.getEngineByName("nashorn");
+
+ // don't define any function.
+ try {
+ engine.eval("");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+
+ Runnable runnable = ((Invocable) engine).getInterface(Runnable.class);
+ if (runnable != null) {
+ fail("runnable is not null!");
+ }
+
+ // now define "run"
+ try {
+ engine.eval("function run() { print('this is run function'); }");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ runnable = ((Invocable) engine).getInterface(Runnable.class);
+ // should not return null now!
+ runnable.run();
+
+ // define only one method of "Foo2"
+ try {
+ engine.eval("function bar() { print('bar function'); }");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+
+ Foo2 foo2 = ((Invocable) engine).getInterface(Foo2.class);
+ if (foo2 != null) {
+ throw new RuntimeException("foo2 is not null!");
+ }
+
+ // now define other method of "Foo2"
+ try {
+ engine.eval("function bar2() { print('bar2 function'); }");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ foo2 = ((Invocable) engine).getInterface(Foo2.class);
+ foo2.bar();
+ foo2.bar2();
+ }
+
+ @Test
+ /**
+ * Try passing non-interface Class object for interface implementation.
+ */
+ public void getNonInterfaceGetInterfaceTest() {
+ final ScriptEngineManager manager = new ScriptEngineManager();
+ final ScriptEngine engine = manager.getEngineByName("nashorn");
+ try {
+ log(Objects.toString(((Invocable) engine).getInterface(Object.class)));
+ fail("Should have thrown IllegalArgumentException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof IllegalArgumentException)) {
+ fail("IllegalArgumentException expected, got " + exp);
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that we can get interface out of a script object even after
+ * switching to use different ScriptContext.
+ */
+ public void getInterfaceDifferentContext() {
+ ScriptEngineManager m = new ScriptEngineManager();
+ ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ Object obj = e.eval("({ run: function() { } })");
+
+ // change script context
+ ScriptContext ctxt = new SimpleScriptContext();
+ ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
+ e.setContext(ctxt);
+
+ Runnable r = ((Invocable) e).getInterface(obj, Runnable.class);
+ r.run();
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ @Test
+ /**
+ * Check that getInterface on non-script object 'thiz' results in
+ * IllegalArgumentException.
+ */
+ public void getInterfaceNonScriptObjectThizTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ ((Invocable) e).getInterface(new Object(), Runnable.class);
+ fail("should have thrown IllegalArgumentException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof IllegalArgumentException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that getInterface on null 'thiz' results in
+ * IllegalArgumentException.
+ */
+ public void getInterfaceNullThizTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ ((Invocable) e).getInterface(null, Runnable.class);
+ fail("should have thrown IllegalArgumentException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof IllegalArgumentException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that calling getInterface on mirror created by another engine
+ * results in IllegalArgumentException.
+ */
+ public void getInterfaceMixEnginesTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine engine1 = m.getEngineByName("nashorn");
+ final ScriptEngine engine2 = m.getEngineByName("nashorn");
+
+ try {
+ Object obj = engine1.eval("({ run: function() {} })");
+ // pass object from engine1 to engine2 as 'thiz' for getInterface
+ ((Invocable) engine2).getInterface(obj, Runnable.class);
+ fail("should have thrown IllegalArgumentException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof IllegalArgumentException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * check that null function name results in NPE.
+ */
+ public void invokeFunctionNullNameTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ final Object res = ((Invocable) e).invokeFunction(null);
+ fail("should have thrown NPE");
+ } catch (final Exception exp) {
+ if (!(exp instanceof NullPointerException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that attempt to call missing function results in
+ * NoSuchMethodException.
+ */
+ public void invokeFunctionMissingTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ final Object res = ((Invocable) e).invokeFunction("NonExistentFunc");
+ fail("should have thrown NoSuchMethodException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof NoSuchMethodException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ /**
+ * Check that invokeFunction calls functions only from current context's
+ * Bindings.
+ */
+ public void invokeFunctionDifferentContextTest() {
+ ScriptEngineManager m = new ScriptEngineManager();
+ ScriptEngine e = m.getEngineByName("nashorn");
+
+ try {
+ // define an object with method on it
+ Object obj = e.eval("function hello() { return 'Hello World!'; }");
+ final ScriptContext ctxt = new SimpleScriptContext();
+ ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
+ // change engine's current context
+ e.setContext(ctxt);
+
+ ((Invocable) e).invokeFunction("hello"); // no 'hello' in new context!
+ fail("should have thrown NoSuchMethodException");
+ } catch (final Exception exp) {
+ if (!(exp instanceof NoSuchMethodException)) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+ }
+
+ @Test
+ public void invokeFunctionExceptionTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ e.eval("function func() { throw new TypeError(); }");
+ } catch (final Throwable t) {
+ t.printStackTrace();
+ fail(t.getMessage());
+ }
+
+ try {
+ ((Invocable) e).invokeFunction("func");
+ fail("should have thrown exception");
+ } catch (final ScriptException se) {
+ // ECMA TypeError property wrapped as a ScriptException
+ log("got " + se + " as expected");
+ } catch (final Throwable t) {
+ t.printStackTrace();
+ fail(t.getMessage());
+ }
+ }
+
+ @Test
+ public void invokeMethodExceptionTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ e.eval("var sobj = {}; sobj.foo = function func() { throw new TypeError(); }");
+ } catch (final Throwable t) {
+ t.printStackTrace();
+ fail(t.getMessage());
+ }
+
+ try {
+ final Object sobj = e.get("sobj");
+ ((Invocable) e).invokeMethod(sobj, "foo");
+ fail("should have thrown exception");
+ } catch (final ScriptException se) {
+ // ECMA TypeError property wrapped as a ScriptException
+ log("got " + se + " as expected");
+ } catch (final Throwable t) {
+ t.printStackTrace();
+ fail(t.getMessage());
+ }
+ }
+
+ @Test
+ /**
+ * Tests whether invocation of a JavaScript method through a variable arity
+ * Java method will pass the vararg array. Both non-vararg and vararg
+ * JavaScript methods are tested.
+ *
+ * @throws ScriptException
+ */
+ public void variableArityInterfaceTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ e.eval(
+ "function test1(i, strings) {"
+ + " return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)"
+ + "}"
+ + "function test2() {"
+ + " return 'arguments[0] == ' + arguments[0] + ', arguments[1] instanceof java.lang.String[] == ' + (arguments[1] instanceof Java.type('java.lang.String[]')) + ', arguments[1] == ' + java.util.Arrays.toString(arguments[1])"
+ + "}");
+ final VariableArityTestInterface itf = ((Invocable) e).getInterface(VariableArityTestInterface.class);
+ Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]");
+ Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java Fri Aug 23 12:44:01 2013 +0200
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.api.scripting;
+
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+import javax.script.SimpleScriptContext;
+import org.testng.Assert;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import org.testng.annotations.Test;
+
+/**
+ * Tests for jsr223 Bindings "scope" (engine, global scopes)
+ */
+public class ScopeTest {
+
+ @Test
+ public void createBindingsTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ Bindings b = e.createBindings();
+ b.put("foo", 42.0);
+ Object res = null;
+ try {
+ res = e.eval("foo == 42.0", b);
+ } catch (final ScriptException | NullPointerException se) {
+ se.printStackTrace();
+ fail(se.getMessage());
+ }
+
+ assertEquals(res, Boolean.TRUE);
+ }
+
+ @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");
+ }
+
+ @Test
+ public void multiGlobalTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ try {
+ Object obj1 = e.eval("Object");
+ Object obj2 = e.eval("Object", newCtxt);
+ Assert.assertNotEquals(obj1, obj2);
+ Assert.assertNotNull(obj1);
+ Assert.assertNotNull(obj2);
+ Assert.assertEquals(obj1.toString(), obj2.toString());
+
+ e.eval("x = 'hello'");
+ e.eval("x = 'world'", newCtxt);
+ Object x1 = e.getContext().getAttribute("x");
+ Object x2 = newCtxt.getAttribute("x");
+ Assert.assertNotEquals(x1, x2);
+ Assert.assertEquals(x1, "hello");
+ Assert.assertEquals(x2, "world");
+
+ x1 = e.eval("x");
+ x2 = e.eval("x", newCtxt);
+ Assert.assertNotEquals(x1, x2);
+ Assert.assertEquals(x1, "hello");
+ Assert.assertEquals(x2, "world");
+
+ final ScriptContext origCtxt = e.getContext();
+ e.setContext(newCtxt);
+ e.eval("y = new Object()");
+ e.eval("y = new Object()", origCtxt);
+
+ Object y1 = origCtxt.getAttribute("y");
+ Object y2 = newCtxt.getAttribute("y");
+ Assert.assertNotEquals(y1, y2);
+ Assert.assertNotEquals(e.eval("y"), e.eval("y", origCtxt));
+ Assert.assertEquals("[object Object]", y1.toString());
+ Assert.assertEquals("[object Object]", y2.toString());
+ } catch (final ScriptException se) {
+ se.printStackTrace();
+ fail(se.getMessage());
+ }
+ }
+
+ @Test
+ public void userEngineScopeBindingsTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ e.eval("function func() {}");
+
+ final ScriptContext newContext = new SimpleScriptContext();
+ newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
+ // we are using a new bindings - so it should have 'func' defined
+ Object value = e.eval("typeof func", newContext);
+ assertTrue(value.equals("undefined"));
+ }
+
+ @Test
+ public void userEngineScopeBindingsNoLeakTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final ScriptContext newContext = new SimpleScriptContext();
+ newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
+ e.eval("function foo() {}", newContext);
+
+ // in the default context's ENGINE_SCOPE, 'foo' shouldn't exist
+ assertTrue(e.eval("typeof foo").equals("undefined"));
+ }
+
+ @Test
+ public void userEngineScopeBindingsRetentionTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final ScriptContext newContext = new SimpleScriptContext();
+ newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
+ e.eval("function foo() {}", newContext);
+
+ // definition retained with user's ENGINE_SCOPE Binding
+ assertTrue(e.eval("typeof foo", newContext).equals("function"));
+
+ final Bindings oldBindings = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
+ // but not in another ENGINE_SCOPE binding
+ newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
+ assertTrue(e.eval("typeof foo", newContext).equals("undefined"));
+
+ // restore ENGINE_SCOPE and check again
+ newContext.setBindings(oldBindings, ScriptContext.ENGINE_SCOPE);
+ assertTrue(e.eval("typeof foo", newContext).equals("function"));
+ }
+
+ @Test
+ // check that engine.js definitions are visible in all new global instances
+ public void checkBuiltinsInNewBindingsTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ // check default global instance has engine.js definitions
+ final Bindings g = (Bindings) e.eval("this");
+ Object value = g.get("__noSuchProperty__");
+ assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
+ value = g.get("print");
+ assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
+
+ // check new global instance created has engine.js definitions
+ Bindings b = e.createBindings();
+ value = b.get("__noSuchProperty__");
+ assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
+ value = b.get("print");
+ assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
+
+ // put a mapping into GLOBAL_SCOPE
+ final Bindings globalScope = e.getContext().getBindings(ScriptContext.GLOBAL_SCOPE);
+ globalScope.put("x", "hello");
+
+ // GLOBAL_SCOPE mapping should be visible from default ScriptContext eval
+ assertTrue(e.eval("x").equals("hello"));
+
+ final ScriptContext ctx = new SimpleScriptContext();
+ ctx.setBindings(globalScope, ScriptContext.GLOBAL_SCOPE);
+ ctx.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ // GLOBAL_SCOPE mapping should be visible from non-default ScriptContext eval
+ assertTrue(e.eval("x", ctx).equals("hello"));
+
+ // try some arbitray Bindings for ENGINE_SCOPE
+ Bindings sb = new SimpleBindings();
+ ctx.setBindings(sb, ScriptContext.ENGINE_SCOPE);
+
+ // GLOBAL_SCOPE mapping should be visible from non-default ScriptContext eval
+ assertTrue(e.eval("x", ctx).equals("hello"));
+
+ // engine.js builtins are still defined even with arbitrary Bindings
+ assertTrue(e.eval("typeof print", ctx).equals("function"));
+ assertTrue(e.eval("typeof __noSuchProperty__", ctx).equals("function"));
+
+ // ENGINE_SCOPE definition should 'hide' GLOBAL_SCOPE definition
+ sb.put("x", "newX");
+ assertTrue(e.eval("x", ctx).equals("newX"));
+ }
+}
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Fri Aug 23 12:44:01 2013 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.api.scripting;
import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
@@ -34,21 +33,13 @@
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
import java.util.concurrent.Callable;
-import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
-import javax.script.Invocable;
-import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
-import javax.script.SimpleScriptContext;
-import org.testng.Assert;
import org.testng.annotations.Test;
/**
@@ -239,214 +230,6 @@
}
@Test
- public void createBindingsTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- Bindings b = e.createBindings();
- b.put("foo", 42.0);
- Object res = null;
- try {
- res = e.eval("foo == 42.0", b);
- } catch (final ScriptException | NullPointerException se) {
- se.printStackTrace();
- fail(se.getMessage());
- }
-
- assertEquals(res, Boolean.TRUE);
- }
-
- @Test
- public void getInterfaceTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- final Invocable inv = (Invocable)e;
-
- // try to get interface from global functions
- try {
- e.eval("function run() { print('run'); };");
- final Runnable runnable = inv.getInterface(Runnable.class);
- runnable.run();
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
-
- // try interface on specific script object
- try {
- e.eval("var obj = { run: function() { print('run from obj'); } };");
- Object obj = e.get("obj");
- final Runnable runnable = inv.getInterface(obj, Runnable.class);
- runnable.run();
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
-
- public interface Foo {
- public void bar();
- }
-
- public interface Foo2 extends Foo {
- public void bar2();
- }
-
- @Test
- public void getInterfaceMissingTest() {
- final ScriptEngineManager manager = new ScriptEngineManager();
- final ScriptEngine engine = manager.getEngineByName("nashorn");
-
- // don't define any function.
- try {
- engine.eval("");
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
-
- Runnable runnable = ((Invocable)engine).getInterface(Runnable.class);
- if (runnable != null) {
- fail("runnable is not null!");
- }
-
- // now define "run"
- try {
- engine.eval("function run() { print('this is run function'); }");
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- runnable = ((Invocable)engine).getInterface(Runnable.class);
- // should not return null now!
- runnable.run();
-
- // define only one method of "Foo2"
- try {
- engine.eval("function bar() { print('bar function'); }");
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
-
- Foo2 foo2 = ((Invocable)engine).getInterface(Foo2.class);
- if (foo2 != null) {
- throw new RuntimeException("foo2 is not null!");
- }
-
- // now define other method of "Foo2"
- try {
- engine.eval("function bar2() { print('bar2 function'); }");
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- foo2 = ((Invocable)engine).getInterface(Foo2.class);
- foo2.bar();
- foo2.bar2();
- }
-
- @Test
- /**
- * Try passing non-interface Class object for interface implementation.
- */
- public void getNonInterfaceGetInterfaceTest() {
- final ScriptEngineManager manager = new ScriptEngineManager();
- final ScriptEngine engine = manager.getEngineByName("nashorn");
- try {
- log(Objects.toString(((Invocable)engine).getInterface(Object.class)));
- fail("Should have thrown IllegalArgumentException");
- } catch (final Exception exp) {
- if (! (exp instanceof IllegalArgumentException)) {
- fail("IllegalArgumentException expected, got " + exp);
- }
- }
- }
-
- @Test
- /**
- * Check that we can get interface out of a script object even after
- * switching to use different ScriptContext.
- */
- public void getInterfaceDifferentContext() {
- ScriptEngineManager m = new ScriptEngineManager();
- ScriptEngine e = m.getEngineByName("nashorn");
- try {
- Object obj = e.eval("({ run: function() { } })");
-
- // change script context
- ScriptContext ctxt = new SimpleScriptContext();
- ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
- e.setContext(ctxt);
-
- Runnable r = ((Invocable)e).getInterface(obj, Runnable.class);
- r.run();
- }catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
-
- @Test
- /**
- * Check that getInterface on non-script object 'thiz' results in IllegalArgumentException.
- */
- public void getInterfaceNonScriptObjectThizTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- ((Invocable)e).getInterface(new Object(), Runnable.class);
- fail("should have thrown IllegalArgumentException");
- } catch (final Exception exp) {
- if (! (exp instanceof IllegalArgumentException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
- /**
- * Check that getInterface on null 'thiz' results in IllegalArgumentException.
- */
- public void getInterfaceNullThizTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- ((Invocable)e).getInterface(null, Runnable.class);
- fail("should have thrown IllegalArgumentException");
- } catch (final Exception exp) {
- if (! (exp instanceof IllegalArgumentException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
- /**
- * Check that calling getInterface on mirror created by another engine results in IllegalArgumentException.
- */
- public void getInterfaceMixEnginesTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine engine1 = m.getEngineByName("nashorn");
- final ScriptEngine engine2 = m.getEngineByName("nashorn");
-
- try {
- Object obj = engine1.eval("({ run: function() {} })");
- // pass object from engine1 to engine2 as 'thiz' for getInterface
- ((Invocable)engine2).getInterface(obj, Runnable.class);
- fail("should have thrown IllegalArgumentException");
- } catch (final Exception exp) {
- if (! (exp instanceof IllegalArgumentException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
public void accessGlobalTest() {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
@@ -621,88 +404,6 @@
assertEquals(sw.toString().replaceAll("\r", ""), "hello world\n");
}
- @SuppressWarnings("unchecked")
- @Test
- public void reflectionTest() throws ScriptException {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- e.eval("var obj = { x: 344, y: 'nashorn' }");
-
- int count = 0;
- Map<Object, Object> map = (Map<Object, Object>)e.get("obj");
- assertFalse(map.isEmpty());
- assertTrue(map.keySet().contains("x"));
- assertTrue(map.containsKey("x"));
- assertTrue(map.values().contains("nashorn"));
- assertTrue(map.containsValue("nashorn"));
- for (final Map.Entry<?, ?> ex : map.entrySet()) {
- final Object key = ex.getKey();
- if (key.equals("x")) {
- assertTrue(344 == ((Number)ex.getValue()).doubleValue());
- count++;
- } else if (key.equals("y")) {
- assertEquals(ex.getValue(), "nashorn");
- count++;
- }
- }
- assertEquals(2, count);
- assertEquals(2, map.size());
-
- // add property
- map.put("z", "hello");
- assertEquals(e.eval("obj.z"), "hello");
- assertEquals(map.get("z"), "hello");
- assertTrue(map.keySet().contains("z"));
- assertTrue(map.containsKey("z"));
- assertTrue(map.values().contains("hello"));
- assertTrue(map.containsValue("hello"));
- assertEquals(map.size(), 3);
-
- final Map<Object, Object> newMap = new HashMap<>();
- newMap.put("foo", 23.0);
- newMap.put("bar", true);
- map.putAll(newMap);
-
- assertEquals(e.eval("obj.foo"), 23.0);
- assertEquals(e.eval("obj.bar"), true);
-
- // remove using map method
- map.remove("foo");
- assertEquals(e.eval("typeof obj.foo"), "undefined");
-
- count = 0;
- e.eval("var arr = [ true, 'hello' ]");
- map = (Map<Object, Object>)e.get("arr");
- assertFalse(map.isEmpty());
- assertTrue(map.containsKey("length"));
- assertTrue(map.containsValue("hello"));
- for (final Map.Entry<?, ?> ex : map.entrySet()) {
- final Object key = ex.getKey();
- if (key.equals("0")) {
- assertEquals(ex.getValue(), Boolean.TRUE);
- count++;
- } else if (key.equals("1")) {
- assertEquals(ex.getValue(), "hello");
- count++;
- }
- }
- assertEquals(count, 2);
- assertEquals(map.size(), 2);
-
- // add element
- map.put("2", "world");
- assertEquals(map.get("2"), "world");
- assertEquals(map.size(), 3);
-
- // remove all
- map.clear();
- assertTrue(map.isEmpty());
- assertEquals(e.eval("typeof arr[0]"), "undefined");
- assertEquals(e.eval("typeof arr[1]"), "undefined");
- assertEquals(e.eval("typeof arr[2]"), "undefined");
- }
-
@Test
public void redefineEchoTest() {
final ScriptEngineManager m = new ScriptEngineManager();
@@ -715,150 +416,6 @@
fail(exp.getMessage());
}
}
-
- @Test
- public void invokeMethodTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- e.eval("var Example = function() { this.hello = function() { return 'Hello World!'; };}; myExample = new Example();");
- final Object obj = e.get("myExample");
- final Object res = ((Invocable)e).invokeMethod(obj, "hello");
- assertEquals(res, "Hello World!");
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
-
- @Test
- /**
- * Check that we can call invokeMethod on an object that we got by evaluating
- * script with different Context set.
- */
- public void invokeMethodDifferentContextTest() {
- ScriptEngineManager m = new ScriptEngineManager();
- ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- // define an object with method on it
- Object obj = e.eval("({ hello: function() { return 'Hello World!'; } })");
-
- final ScriptContext ctxt = new SimpleScriptContext();
- ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
- e.setContext(ctxt);
-
- // invoke 'func' on obj - but with current script context changed
- final Object res = ((Invocable)e).invokeMethod(obj, "hello");
- assertEquals(res, "Hello World!");
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
-
- @Test
- /**
- * Check that invokeMethod throws NPE on null method name.
- */
- public void invokeMethodNullNameTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- final Object obj = e.eval("({})");
- final Object res = ((Invocable)e).invokeMethod(obj, null);
- fail("should have thrown NPE");
- } catch (final Exception exp) {
- if (! (exp instanceof NullPointerException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
- /**
- * Check that invokeMethod throws NoSuchMethodException on missing method.
- */
- public void invokeMethodMissingTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- final Object obj = e.eval("({})");
- final Object res = ((Invocable)e).invokeMethod(obj, "nonExistentMethod");
- fail("should have thrown NoSuchMethodException");
- } catch (final Exception exp) {
- if (! (exp instanceof NoSuchMethodException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
- /**
- * Check that calling method on non-script object 'thiz' results in IllegalArgumentException.
- */
- public void invokeMethodNonScriptObjectThizTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- ((Invocable)e).invokeMethod(new Object(), "toString");
- fail("should have thrown IllegalArgumentException");
- } catch (final Exception exp) {
- if (! (exp instanceof IllegalArgumentException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
- /**
- * Check that calling method on null 'thiz' results in IllegalArgumentException.
- */
- public void invokeMethodNullThizTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- ((Invocable)e).invokeMethod(null, "toString");
- fail("should have thrown IllegalArgumentException");
- } catch (final Exception exp) {
- if (! (exp instanceof IllegalArgumentException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
-
- @Test
- /**
- * Check that calling method on mirror created by another engine results in IllegalArgumentException.
- */
- public void invokeMethodMixEnginesTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine engine1 = m.getEngineByName("nashorn");
- final ScriptEngine engine2 = m.getEngineByName("nashorn");
-
- try {
- Object obj = engine1.eval("({ run: function() {} })");
- // pass object from engine1 to engine2 as 'thiz' for invokeMethod
- ((Invocable)engine2).invokeMethod(obj, "run");
- fail("should have thrown IllegalArgumentException");
- } catch (final Exception exp) {
- if (! (exp instanceof IllegalArgumentException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
@Test
public void noEnumerablePropertiesTest() {
final ScriptEngineManager m = new ScriptEngineManager();
@@ -920,308 +477,6 @@
}
@Test
- public void jsobjectTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- try {
- e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }");
- JSObject obj = (JSObject) e.get("obj");
-
- // try basic get on existing properties
- if (! obj.getMember("bar").equals("hello")) {
- fail("obj.bar != 'hello'");
- }
-
- if (! obj.getSlot(1).equals("world")) {
- fail("obj[1] != 'world'");
- }
-
- if (! obj.call("func", new Object[0]).equals("hello")) {
- fail("obj.call('func') != 'hello'");
- }
-
- // try setting properties
- obj.setMember("bar", "new-bar");
- obj.setSlot(1, "new-element-1");
- if (! obj.getMember("bar").equals("new-bar")) {
- fail("obj.bar != 'new-bar'");
- }
-
- if (! obj.getSlot(1).equals("new-element-1")) {
- fail("obj[1] != 'new-element-1'");
- }
-
- // try adding properties
- obj.setMember("prop", "prop-value");
- obj.setSlot(12, "element-12");
- if (! obj.getMember("prop").equals("prop-value")) {
- fail("obj.prop != 'prop-value'");
- }
-
- if (! obj.getSlot(12).equals("element-12")) {
- fail("obj[12] != 'element-12'");
- }
-
- // delete properties
- obj.removeMember("prop");
- if ("prop-value".equals(obj.getMember("prop"))) {
- fail("obj.prop is not deleted!");
- }
-
- // Simple eval tests
- assertEquals(obj.eval("typeof Object"), "function");
- assertEquals(obj.eval("'nashorn'.substring(3)"), "horn");
- } catch (final Exception exp) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
-
- @Test
- /**
- * check that null function name results in NPE.
- */
- public void invokeFunctionNullNameTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- final Object res = ((Invocable)e).invokeFunction(null);
- fail("should have thrown NPE");
- } catch (final Exception exp) {
- if (! (exp instanceof NullPointerException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
- /**
- * Check that attempt to call missing function results in NoSuchMethodException.
- */
- public void invokeFunctionMissingTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- final Object res = ((Invocable)e).invokeFunction("NonExistentFunc");
- fail("should have thrown NoSuchMethodException");
- } catch (final Exception exp) {
- if (! (exp instanceof NoSuchMethodException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
- /**
- * Check that invokeFunction calls functions only from current context's Bindings.
- */
- public void invokeFunctionDifferentContextTest() {
- ScriptEngineManager m = new ScriptEngineManager();
- ScriptEngine e = m.getEngineByName("nashorn");
-
- try {
- // define an object with method on it
- Object obj = e.eval("function hello() { return 'Hello World!'; }");
- final ScriptContext ctxt = new SimpleScriptContext();
- ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
- // change engine's current context
- e.setContext(ctxt);
-
- ((Invocable)e).invokeFunction("hello"); // no 'hello' in new context!
- fail("should have thrown NoSuchMethodException");
- } catch (final Exception exp) {
- if (! (exp instanceof NoSuchMethodException)) {
- exp.printStackTrace();
- fail(exp.getMessage());
- }
- }
- }
-
- @Test
- public void invokeFunctionExceptionTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- try {
- e.eval("function func() { throw new TypeError(); }");
- } catch (final Throwable t) {
- t.printStackTrace();
- fail(t.getMessage());
- }
-
- try {
- ((Invocable)e).invokeFunction("func");
- fail("should have thrown exception");
- } catch (final ScriptException se) {
- // ECMA TypeError property wrapped as a ScriptException
- log("got " + se + " as expected");
- } catch (final Throwable t) {
- t.printStackTrace();
- fail(t.getMessage());
- }
- }
-
- @Test
- public void invokeMethodExceptionTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- try {
- e.eval("var sobj = {}; sobj.foo = function func() { throw new TypeError(); }");
- } catch (final Throwable t) {
- t.printStackTrace();
- fail(t.getMessage());
- }
-
- try {
- final Object sobj = e.get("sobj");
- ((Invocable)e).invokeMethod(sobj, "foo");
- fail("should have thrown exception");
- } catch (final ScriptException se) {
- // ECMA TypeError property wrapped as a ScriptException
- log("got " + se + " as expected");
- } catch (final Throwable t) {
- t.printStackTrace();
- fail(t.getMessage());
- }
- }
-
- @Test
- public void scriptObjectMirrorToStringTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- try {
- Object obj = e.eval("new TypeError('wrong type')");
- assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value");
- } catch (final Throwable t) {
- t.printStackTrace();
- fail(t.getMessage());
- }
-
- try {
- Object obj = e.eval("function func() { print('hello'); }");
- assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value");
- } catch (final Throwable t) {
- t.printStackTrace();
- 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");
- }
-
- @Test
- public void multiGlobalTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- final Bindings b = e.createBindings();
- final ScriptContext newCtxt = new SimpleScriptContext();
- newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
-
- try {
- Object obj1 = e.eval("Object");
- Object obj2 = e.eval("Object", newCtxt);
- Assert.assertNotEquals(obj1, obj2);
- Assert.assertNotNull(obj1);
- Assert.assertNotNull(obj2);
- Assert.assertEquals(obj1.toString(), obj2.toString());
-
- e.eval("x = 'hello'");
- e.eval("x = 'world'", newCtxt);
- Object x1 = e.getContext().getAttribute("x");
- Object x2 = newCtxt.getAttribute("x");
- Assert.assertNotEquals(x1, x2);
- Assert.assertEquals(x1, "hello");
- Assert.assertEquals(x2, "world");
-
- x1 = e.eval("x");
- x2 = e.eval("x", newCtxt);
- Assert.assertNotEquals(x1, x2);
- Assert.assertEquals(x1, "hello");
- Assert.assertEquals(x2, "world");
-
- final ScriptContext origCtxt = e.getContext();
- e.setContext(newCtxt);
- e.eval("y = new Object()");
- e.eval("y = new Object()", origCtxt);
-
- Object y1 = origCtxt.getAttribute("y");
- Object y2 = newCtxt.getAttribute("y");
- Assert.assertNotEquals(y1, y2);
- Assert.assertNotEquals(e.eval("y"), e.eval("y", origCtxt));
- Assert.assertEquals("[object Object]", y1.toString());
- Assert.assertEquals("[object Object]", y2.toString());
- } catch (final ScriptException se) {
- se.printStackTrace();
- fail(se.getMessage());
- }
- }
-
- @Test
- /**
- * Tests whether invocation of a JavaScript method through a variable arity Java method will pass the vararg array.
- * Both non-vararg and vararg JavaScript methods are tested.
- * @throws ScriptException
- */
- public void variableArityInterfaceTest() throws ScriptException {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- e.eval(
- "function test1(i, strings) {" +
- " return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)" +
- "}" +
- "function test2() {" +
- " return 'arguments[0] == ' + arguments[0] + ', arguments[1] instanceof java.lang.String[] == ' + (arguments[1] instanceof Java.type('java.lang.String[]')) + ', arguments[1] == ' + java.util.Arrays.toString(arguments[1])" +
- "}"
- );
- final VariableArityTestInterface itf = ((Invocable)e).getInterface(VariableArityTestInterface.class);
- Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]");
- Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]");
- }
-
- @Test
// check that print function prints arg followed by newline char
public void printTest() {
final ScriptEngineManager m = new ScriptEngineManager();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java Fri Aug 23 12:44:01 2013 +0200
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.api.scripting;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import org.testng.annotations.Test;
+
+/**
+ * Tests to check jdk.nashorn.api.scripting.ScriptObjectMirror API.
+ */
+public class ScriptObjectMirrorTest {
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void reflectionTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ e.eval("var obj = { x: 344, y: 'nashorn' }");
+
+ int count = 0;
+ Map<Object, Object> map = (Map<Object, Object>) e.get("obj");
+ assertFalse(map.isEmpty());
+ assertTrue(map.keySet().contains("x"));
+ assertTrue(map.containsKey("x"));
+ assertTrue(map.values().contains("nashorn"));
+ assertTrue(map.containsValue("nashorn"));
+ for (final Map.Entry<?, ?> ex : map.entrySet()) {
+ final Object key = ex.getKey();
+ if (key.equals("x")) {
+ assertTrue(344 == ((Number) ex.getValue()).doubleValue());
+ count++;
+ } else if (key.equals("y")) {
+ assertEquals(ex.getValue(), "nashorn");
+ count++;
+ }
+ }
+ assertEquals(2, count);
+ assertEquals(2, map.size());
+
+ // add property
+ map.put("z", "hello");
+ assertEquals(e.eval("obj.z"), "hello");
+ assertEquals(map.get("z"), "hello");
+ assertTrue(map.keySet().contains("z"));
+ assertTrue(map.containsKey("z"));
+ assertTrue(map.values().contains("hello"));
+ assertTrue(map.containsValue("hello"));
+ assertEquals(map.size(), 3);
+
+ final Map<Object, Object> newMap = new HashMap<>();
+ newMap.put("foo", 23.0);
+ newMap.put("bar", true);
+ map.putAll(newMap);
+
+ assertEquals(e.eval("obj.foo"), 23.0);
+ assertEquals(e.eval("obj.bar"), true);
+
+ // remove using map method
+ map.remove("foo");
+ assertEquals(e.eval("typeof obj.foo"), "undefined");
+
+ count = 0;
+ e.eval("var arr = [ true, 'hello' ]");
+ map = (Map<Object, Object>) e.get("arr");
+ assertFalse(map.isEmpty());
+ assertTrue(map.containsKey("length"));
+ assertTrue(map.containsValue("hello"));
+ for (final Map.Entry<?, ?> ex : map.entrySet()) {
+ final Object key = ex.getKey();
+ if (key.equals("0")) {
+ assertEquals(ex.getValue(), Boolean.TRUE);
+ count++;
+ } else if (key.equals("1")) {
+ assertEquals(ex.getValue(), "hello");
+ count++;
+ }
+ }
+ assertEquals(count, 2);
+ assertEquals(map.size(), 2);
+
+ // add element
+ map.put("2", "world");
+ assertEquals(map.get("2"), "world");
+ assertEquals(map.size(), 3);
+
+ // remove all
+ map.clear();
+ assertTrue(map.isEmpty());
+ assertEquals(e.eval("typeof arr[0]"), "undefined");
+ assertEquals(e.eval("typeof arr[1]"), "undefined");
+ assertEquals(e.eval("typeof arr[2]"), "undefined");
+ }
+
+ @Test
+ public void jsobjectTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }");
+ JSObject obj = (JSObject) e.get("obj");
+
+ // try basic get on existing properties
+ if (!obj.getMember("bar").equals("hello")) {
+ fail("obj.bar != 'hello'");
+ }
+
+ if (!obj.getSlot(1).equals("world")) {
+ fail("obj[1] != 'world'");
+ }
+
+ if (!obj.call("func", new Object[0]).equals("hello")) {
+ fail("obj.call('func') != 'hello'");
+ }
+
+ // try setting properties
+ obj.setMember("bar", "new-bar");
+ obj.setSlot(1, "new-element-1");
+ if (!obj.getMember("bar").equals("new-bar")) {
+ fail("obj.bar != 'new-bar'");
+ }
+
+ if (!obj.getSlot(1).equals("new-element-1")) {
+ fail("obj[1] != 'new-element-1'");
+ }
+
+ // try adding properties
+ obj.setMember("prop", "prop-value");
+ obj.setSlot(12, "element-12");
+ if (!obj.getMember("prop").equals("prop-value")) {
+ fail("obj.prop != 'prop-value'");
+ }
+
+ if (!obj.getSlot(12).equals("element-12")) {
+ fail("obj[12] != 'element-12'");
+ }
+
+ // delete properties
+ obj.removeMember("prop");
+ if ("prop-value".equals(obj.getMember("prop"))) {
+ fail("obj.prop is not deleted!");
+ }
+
+ // Simple eval tests
+ assertEquals(obj.eval("typeof Object"), "function");
+ assertEquals(obj.eval("'nashorn'.substring(3)"), "horn");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ @Test
+ public void scriptObjectMirrorToStringTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ Object obj = e.eval("new TypeError('wrong type')");
+ assertEquals(obj.toString(), "TypeError: wrong type", "toString returns wrong value");
+ } catch (final Throwable t) {
+ t.printStackTrace();
+ fail(t.getMessage());
+ }
+
+ try {
+ Object obj = e.eval("function func() { print('hello'); }");
+ assertEquals(obj.toString(), "function func() { print('hello'); }", "toString returns wrong value");
+ } catch (final Throwable t) {
+ t.printStackTrace();
+ fail(t.getMessage());
+ }
+ }
+
+ @Test
+ public void mirrorNewObjectGlobalFunctionTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final ScriptEngine e2 = m.getEngineByName("nashorn");
+
+ e.eval("function func() {}");
+ e2.put("foo", e.get("func"));
+ final Object e2global = e2.eval("this");
+ final Object newObj = ((ScriptObjectMirror) e2global).newObject("foo");
+ assertTrue(newObj instanceof ScriptObjectMirror);
+ }
+
+ @Test
+ public void mirrorNewObjectInstanceFunctionTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final ScriptEngine e2 = m.getEngineByName("nashorn");
+
+ e.eval("function func() {}");
+ e2.put("func", e.get("func"));
+ final Object e2obj = e2.eval("({ foo: func })");
+ final Object newObj = ((ScriptObjectMirror) e2obj).newObject("foo");
+ assertTrue(newObj instanceof ScriptObjectMirror);
+ }
+}
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java Fri Aug 23 12:43:32 2013 +0200
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java Fri Aug 23 12:44:01 2013 +0200
@@ -32,7 +32,10 @@
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
+import javax.script.ScriptContext;
import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+import javax.script.SimpleScriptContext;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import org.testng.annotations.Test;
@@ -196,4 +199,25 @@
}
fail("Cannot find nashorn factory!");
}
+
+ @Test
+ public void globalPerEngineTest() throws ScriptException {
+ final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
+ final String[] options = new String[] { "--global-per-engine" };
+ final ScriptEngine e = fac.getScriptEngine(options);
+
+ e.eval("function foo() {}");
+
+ final ScriptContext newCtx = new SimpleScriptContext();
+ newCtx.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
+
+ // all global definitions shared and so 'foo' should be
+ // visible in new Bindings as well.
+ assertTrue(e.eval("typeof foo", newCtx).equals("function"));
+
+ e.eval("function bar() {}", newCtx);
+
+ // bar should be visible in default context
+ assertTrue(e.eval("typeof bar").equals("function"));
+ }
}