# HG changeset patch # User sundar # Date 1389275614 -19800 # Node ID 5181d08e3440ed05831f321972d88987d12b9968 # Parent ab34b295a7020a7d0c1e76f8fee70bcff8cbe0fa 8031359: Invocable.getInterface() works incorrectly if interface has default methods Reviewed-by: attila, hannesw diff -r ab34b295a702 -r 5181d08e3440 nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Jan 08 17:51:47 2014 +0530 +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Thu Jan 09 19:23:34 2014 +0530 @@ -626,6 +626,11 @@ continue; } + // skip check for default methods - non-abstract, interface methods + if (! Modifier.isAbstract(method.getModifiers())) { + continue; + } + Object obj = sobj.get(method.getName()); if (! (obj instanceof ScriptFunction)) { return false; diff -r ab34b295a702 -r 5181d08e3440 nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Wed Jan 08 17:51:47 2014 +0530 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Thu Jan 09 19:23:34 2014 +0530 @@ -651,7 +651,7 @@ mv.athrow(); } else { // If the super method is not abstract, delegate to it. - emitSuperCall(mv, name, methodDesc); + emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); } final Label setupGlobal = new Label(); @@ -830,12 +830,12 @@ SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes()))); mv.visitCode(); - emitSuperCall(mv, name, methodDesc); + emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); endMethod(mv); } - private void emitSuperCall(final InstructionAdapter mv, final String name, final String methodDesc) { + private void emitSuperCall(final InstructionAdapter mv, final Class owner, final String name, final String methodDesc) { mv.visitVarInsn(ALOAD, 0); int nextParam = 1; final Type methodType = Type.getMethodType(methodDesc); @@ -843,7 +843,13 @@ mv.load(nextParam, t); nextParam += t.getSize(); } - mv.invokespecial(superClassName, name, methodDesc, false); + + // default method - non-abstract, interface method + if (Modifier.isInterface(owner.getModifiers())) { + mv.invokespecial(Type.getInternalName(owner), name, methodDesc, false); + } else { + mv.invokespecial(superClassName, name, methodDesc, false); + } mv.areturn(methodType.getReturnType()); } diff -r ab34b295a702 -r 5181d08e3440 nashorn/test/script/basic/JDK-8031359.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8031359.js Thu Jan 09 19:23:34 2014 +0530 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010, 2014, 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-8031359: Invocable.getInterface() works incorrectly if interface has default methods + * + * @test + * @run + */ + +var func = new java.util.function.Function() { + apply: function(arg) { + print("func called with " + arg); + return arg.toUpperCase(); + } +}; + +// Function.andThen is a default method +func.andThen(func)("hello"); + +// Function.compose is another default method +func.compose(new java.util.function.Function() { + apply: function(arg) { + print("compose called with " + arg); + return arg.charAt(0); + } +})("hello"); + +var func2 = new java.util.function.Function() { + apply: function(arg) { + print("I am func2: " + arg); + return arg; + }, + + andThen: function(func) { + print("This is my andThen!"); + return func; + } +}; + +func2.apply("hello"); +func2.andThen(func); diff -r ab34b295a702 -r 5181d08e3440 nashorn/test/script/basic/JDK-8031359.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8031359.js.EXPECTED Thu Jan 09 19:23:34 2014 +0530 @@ -0,0 +1,6 @@ +func called with hello +func called with HELLO +compose called with hello +func called with h +I am func2: hello +This is my andThen! diff -r ab34b295a702 -r 5181d08e3440 nashorn/test/src/jdk/nashorn/api/scripting/InvocableTest.java --- a/nashorn/test/src/jdk/nashorn/api/scripting/InvocableTest.java Wed Jan 08 17:51:47 2014 +0530 +++ b/nashorn/test/src/jdk/nashorn/api/scripting/InvocableTest.java Thu Jan 09 19:23:34 2014 +0530 @@ -26,6 +26,7 @@ package jdk.nashorn.api.scripting; import java.util.Objects; +import java.util.function.Function; import javax.script.Invocable; import javax.script.ScriptContext; import javax.script.ScriptEngine; @@ -522,4 +523,16 @@ 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 + @SuppressWarnings("unchecked") + public void defaultMethodTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Invocable inv = (Invocable) e; + + Object obj = e.eval("({ apply: function(arg) { return arg.toUpperCase(); }})"); + Function func = inv.getInterface(obj, Function.class); + assertEquals(func.apply("hello"), "HELLO"); + } }