8031359: Invocable.getInterface() works incorrectly if interface has default methods

Reviewed-by: attila, hannesw
This commit is contained in:
Athijegannathan Sundararajan 2014-01-09 19:23:34 +05:30
parent 9304f8da29
commit 305de05b44
5 changed files with 96 additions and 4 deletions

View File

@ -626,6 +626,11 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
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;

View File

@ -651,7 +651,7 @@ final class JavaAdapterBytecodeGenerator {
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 @@ final class JavaAdapterBytecodeGenerator {
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 @@ final class JavaAdapterBytecodeGenerator {
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());
}

View File

@ -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);

View File

@ -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!

View File

@ -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 @@ public class InvocableTest {
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<String, String> func = inv.getInterface(obj, Function.class);
assertEquals(func.apply("hello"), "HELLO");
}
}