From bdcffc23f7d510197930056340e7d400e1c5a33a Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 31 Jan 2013 20:07:40 +0530 Subject: [PATCH] 8007286: Add JavaAdapter and importPackage to compatibility script Reviewed-by: lagergren, jlaskey --- .../api/scripting/NashornException.java | 3 + .../api/scripting/NashornScriptEngine.java | 43 +------ .../nashorn/api/scripting/resources/engine.js | 10 -- .../nashorn/internal/parser/TokenLookup.java | 2 +- .../nashorn/internal/parser/TokenType.java | 2 +- .../internal/runtime/ECMAException.java | 8 +- .../internal/runtime/PropertyHashMap.java | 2 +- .../internal/runtime/ScriptObject.java | 10 +- .../runtime/resources/mozilla_compat.js | 50 ++++++++ nashorn/test/script/basic/importpackage.js | 59 +++++++++ nashorn/test/script/basic/javaadapter.js | 119 ++++++++++++++++++ 11 files changed, 242 insertions(+), 66 deletions(-) create mode 100644 nashorn/test/script/basic/importpackage.js create mode 100644 nashorn/test/script/basic/javaadapter.js diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornException.java b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java index 75a62a802f4..eae8c3bf127 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornException.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java @@ -44,6 +44,9 @@ public class NashornException extends RuntimeException { // script column number private int column; + // script source name used for "engine.js" + protected static final String ENGINE_SCRIPT_SOURCE_NAME = "nashorn:engine/resources/engine.js"; + /** * Constructor * diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 34425883dff..02b7e911bbd 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -242,41 +242,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C return UNDEFINED; } - /** - * This hook is used to call js global functions exposed from Java code. - * - * @param self 'this' passed from the script - * @param ctxt current ScriptContext in which method is searched - * @param name name of the method - * @param args arguments to be passed to the method - * @return return value of the called method - */ - public Object __noSuchMethod__(final Object self, final ScriptContext ctxt, final String name, final Object args) { - final int scope = ctxt.getAttributesScope(name); - final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt); - Object value; - - if (scope != -1) { - value = ctxt.getAttribute(name, scope); - } else { - if (self == UNDEFINED) { - referenceError(ctxtGlobal, "not.defined", name); - } else { - typeError(ctxtGlobal, "no.such.function", name, ScriptRuntime.safeToString(ctxtGlobal)); - } - return UNDEFINED; - } - - value = ScriptObjectMirror.unwrap(value, ctxtGlobal); - if (value instanceof ScriptFunction) { - return ScriptObjectMirror.unwrap(ScriptRuntime.apply((ScriptFunction)value, ctxtGlobal, args), ctxtGlobal); - } - - typeError(ctxtGlobal, "not.a.function", ScriptRuntime.safeToString(name)); - - return UNDEFINED; - } - private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) { final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE); if (bindings instanceof ScriptObjectMirror) { @@ -320,10 +285,10 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } private void evalEngineScript() throws ScriptException { - evalSupportScript("resources/engine.js"); + evalSupportScript("resources/engine.js", NashornException.ENGINE_SCRIPT_SOURCE_NAME); } - private void evalSupportScript(final String script) throws ScriptException { + private void evalSupportScript(final String script, final String name) throws ScriptException { try { final InputStream is = AccessController.doPrivileged( new PrivilegedExceptionAction() { @@ -333,7 +298,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C return url.openStream(); } }); - put(ScriptEngine.FILENAME, ":" + script); + put(ScriptEngine.FILENAME, name); try (final InputStreamReader isr = new InputStreamReader(is)) { eval(isr); } @@ -427,7 +392,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C // NOTE: FIXME: If this is jrunscript's init.js, we want to run the replacement. // This should go away once we fix jrunscript's copy of init.js. if ("".equals(fileName)) { - evalSupportScript("resources/init.js"); + evalSupportScript("resources/init.js", "nashorn:engine/resources/init.js"); return null; } diff --git a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js index b71f5243713..65b82dfe797 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js @@ -39,16 +39,6 @@ Object.defineProperty(this, "__noSuchProperty__", { } }); -Object.defineProperty(this, "__noSuchMethod__", { - configurable: true, - enumerable: false, - writable: true, - value: function (name, args) { - 'use strict'; - return engine.__noSuchMethod__(this, context, name, args); - } -}); - function print(str) { var writer = context.getWriter(); if (! (writer instanceof java.io.PrintWriter)) { diff --git a/nashorn/src/jdk/nashorn/internal/parser/TokenLookup.java b/nashorn/src/jdk/nashorn/internal/parser/TokenLookup.java index 1598b41b09e..56bd37c4898 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/TokenLookup.java +++ b/nashorn/src/jdk/nashorn/internal/parser/TokenLookup.java @@ -32,7 +32,7 @@ import static jdk.nashorn.internal.parser.TokenType.IDENT; * Fast lookup of operators and keywords. * */ -public class TokenLookup { +public final class TokenLookup { /** * Lookup table for tokens. */ diff --git a/nashorn/src/jdk/nashorn/internal/parser/TokenType.java b/nashorn/src/jdk/nashorn/internal/parser/TokenType.java index d8a0dbdb59f..8cc0ee332db 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/TokenType.java +++ b/nashorn/src/jdk/nashorn/internal/parser/TokenType.java @@ -275,7 +275,7 @@ public enum TokenType { return name != null && name.length() > 0 && name.charAt(0) == c; } - public static TokenType[] getValues() { + static TokenType[] getValues() { return values; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java b/nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java index c554cd34755..04082455732 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java @@ -58,15 +58,9 @@ public final class ECMAException extends NashornException { /** We assume that compiler generates script classes into the known package. */ private static final String scriptPackage; - - /** Package (internal) name where Nashorn script engine implementation lives */ - private static final String enginePackageInternal; - static { String name = JS$.class.getName(); scriptPackage = name.substring(0, name.lastIndexOf('.')); - name = NashornScriptEngine.class.getName(); - enginePackageInternal = name.substring(0, name.lastIndexOf('.')).replace(".", "/"); } /** Object thrown. */ @@ -168,7 +162,7 @@ public final class ECMAException extends NashornException { * also, we don't want to report JavaScript code that lives in script engine implementation * We want to report only user's own scripts and not any of our own scripts like "engine.js" */ - return source != null && !source.endsWith(".java") && !source.contains(enginePackageInternal); + return source != null && !source.endsWith(".java") && !source.contains(ENGINE_SCRIPT_SOURCE_NAME); } return false; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java index 2ae1820dc9f..9759caa2c86 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java @@ -268,7 +268,7 @@ public final class PropertyHashMap implements Map { * * @return Array of all properties. */ - public Property[] getProperties() { + Property[] getProperties() { if (properties == null) { final Property[] array = new Property[size]; int i = size; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 2536f7c932f..86bc0afcd4f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -1937,11 +1937,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr final boolean scopeCall = isScope() && NashornCallSiteDescriptor.isScope(desc); if (find == null) { - if (scopeCall) { - ECMAErrors.referenceError("not.defined", name); - throw new AssertionError(); // never reached - } - return createEmptyGetter(desc, name); + return noSuchProperty(desc, request); } final ScriptFunction func = (ScriptFunction)getObjectValue(find); @@ -3335,10 +3331,10 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } /** This is updated only in debug mode - counts number of {@code ScriptObject} instances created */ - protected static int count; + private static int count; /** This is updated only in debug mode - counts number of {@code ScriptObject} instances created that are scope */ - protected static int scopeCount; + private static int scopeCount; /** * Get number of {@code ScriptObject} instances created. If not running in debug diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js index fa16a173978..15c67f9419b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js @@ -27,6 +27,56 @@ * often used functionality is supported. */ +// JavaAdapter +Object.defineProperty(this, "JavaAdapter", { + configurable: true, enumerable: false, writable: true, + value: function() { + if (arguments.length < 2) { + throw new TypeError("JavaAdapter requires atleast two arguments"); + } + + var types = Array.prototype.slice.call(arguments, 0, arguments.length - 1); + var NewType = Java.extend.apply(Java, types); + return new NewType(arguments[arguments.length - 1]); + } +}); + +// importPackage +Object.defineProperty(this, "importPackage", { + configurable: true, enumerable: false, writable: true, + value: (function() { + var _packages = []; + var global = this; + var oldNoSuchProperty = global.__noSuchProperty__; + global.__noSuchProperty__ = function(name) { + for (var i in _packages) { + try { + var type = Java.type(_packages[i] + "." + name); + global[name] = type; + return type; + } catch (e) {} + } + + return oldNoSuchProperty? oldNoSuchProperty(name) : undefined; + } + + var prefix = "[JavaPackage "; + return function() { + for (var i in arguments) { + var pkgName = arguments[i]; + if ((typeof pkgName) != 'string') { + pkgName = String(pkgName); + // extract name from JavaPackage object + if (pkgName.startsWith(prefix)) { + pkgName = pkgName.substring(prefix.length, pkgName.length - 1); + } + } + _packages.push(pkgName); + } + } + })() +}); + // Object.prototype.__defineGetter__ Object.defineProperty(Object.prototype, "__defineGetter__", { configurable: true, enumerable: false, writable: true, diff --git a/nashorn/test/script/basic/importpackage.js b/nashorn/test/script/basic/importpackage.js new file mode 100644 index 00000000000..9a2b3a3e8c3 --- /dev/null +++ b/nashorn/test/script/basic/importpackage.js @@ -0,0 +1,59 @@ +/* + * 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. + */ + +/** + * Test to check importPackage function. + * + * @test + * @run + */ + +try { + load("nashorn:mozilla_compat.js"); +} catch (e) { +} + +importPackage(java.util); + +var m = new HashMap(); +if (!(m instanceof java.util.HashMap)) { + fail("expected 'm' to be a java.util.HashMap instance"); +} + +function checkJavaClass(cls) { + if (! Java.isType(cls)) { + fail(cls + " is not a Java class"); + } +} + +importPackage(java.lang.reflect, javax.script); +checkJavaClass(Method); +checkJavaClass(Field); +checkJavaClass(Constructor); +checkJavaClass(ScriptContext); +checkJavaClass(ScriptEngine); + +var bindings = new SimpleBindings(); +if (!(bindings instanceof javax.script.SimpleBindings)) { + fail("expected 'bindings' to be a javax.script.SimpleBindings instance"); +} diff --git a/nashorn/test/script/basic/javaadapter.js b/nashorn/test/script/basic/javaadapter.js new file mode 100644 index 00000000000..484a5d24d61 --- /dev/null +++ b/nashorn/test/script/basic/javaadapter.js @@ -0,0 +1,119 @@ +/* + * 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. + */ + +/** + * Test to check JavaAdapter constructor. + * + * @test + * @run + */ + +try { + load("nashorn:mozilla_compat.js"); +} catch (e) { +} + +// try various JavaAdapter cases + +// Single interface +var runReached = false; +var r = new JavaAdapter(java.lang.Runnable) { + run: function() { + runReached = true; + } +}; + +r.run(); +if (! runReached) { + fail("run was not called"); +} + +if (! (r instanceof java.lang.Runnable)) { + fail("r is not a Runnable"); +} + +// Multiple intefaces +var runReached = false; +var actionPerformedReached = false; + +var obj = new JavaAdapter(java.awt.event.ActionListener, java.lang.Runnable) { + actionPerformed : function(e) { + actionPerformedReached = true; + }, + + run: function() { + runReached = true; + } +}; + +obj.actionPerformed(null); +if (! actionPerformedReached) { + fail("actionPerformed was not called"); +} + +obj.run(); +if (! runReached) { + fail("run was not called"); +} + +if (! (obj instanceof java.lang.Runnable)) { + fail("obj is not a Runnable"); +} + +if (! (obj instanceof java.awt.event.ActionListener)) { + fail("obj is not an ActionListener"); +} + +// Single class +var obj = new JavaAdapter(java.lang.Object) { + toString: function() { return "I am an Object"; } +}; + +if (! (obj instanceof java.lang.Object)) { + fail("obj is not an instance of java.lang.Object"); +} + +if (obj.toString() != "I am an Object") { + fail("Object.toString did not get called"); +} + +// Single class and single interface +var runReached = false; +var obj = new JavaAdapter(java.lang.Object, java.lang.Runnable) { + run: function() { + runReached = true; + }, + + hashCode: function() { + return 12; + } +}; + +obj.run(); +if (! runReached) { + fail("run was not called"); +} + +if (obj.hashCode() != 12) { + fail("hashCode does not return 12"); +}