8068901: Surprising behavior with more than one functional interface on a class
8068903: Can't invoke vararg @FunctionalInterface methods Reviewed-by: attila, hannesw
This commit is contained in:
parent
9404b65ba8
commit
5c04be3588
@ -189,7 +189,7 @@ public final class Bootstrap {
|
||||
* @return true if the obj is an instance of @FunctionalInterface interface
|
||||
*/
|
||||
public static boolean isFunctionalInterfaceObject(final Object obj) {
|
||||
return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethod(obj.getClass()) != null);
|
||||
return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethodName(obj.getClass()) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,10 +79,10 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
}
|
||||
|
||||
// cache of @FunctionalInterface method of implementor classes
|
||||
private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() {
|
||||
private static final ClassValue<String> FUNCTIONAL_IFACE_METHOD_NAME = new ClassValue<String>() {
|
||||
@Override
|
||||
protected Method computeValue(final Class<?> type) {
|
||||
return findFunctionalInterfaceMethod(type);
|
||||
protected String computeValue(final Class<?> type) {
|
||||
return findFunctionalInterfaceMethodName(type);
|
||||
}
|
||||
};
|
||||
|
||||
@ -107,19 +107,21 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
// annotated interface. This way Java method, constructor references or
|
||||
// implementations of java.util.function.* interfaces can be called as though
|
||||
// those are script functions.
|
||||
final Method m = getFunctionalInterfaceMethod(self.getClass());
|
||||
if (m != null) {
|
||||
final String name = getFunctionalInterfaceMethodName(self.getClass());
|
||||
if (name != null) {
|
||||
final MethodType callType = desc.getMethodType();
|
||||
// 'callee' and 'thiz' passed from script + actual arguments
|
||||
if (callType.parameterCount() != m.getParameterCount() + 2) {
|
||||
throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
|
||||
}
|
||||
return new GuardedInvocation(
|
||||
// drop 'thiz' passed from the script.
|
||||
MH.dropArguments(linkerServices.filterInternalObjects(desc.getLookup().unreflect(m)), 1,
|
||||
callType.parameterType(1)), Guards.getInstanceOfGuard(
|
||||
m.getDeclaringClass())).asTypeSafeReturn(
|
||||
new NashornBeansLinkerServices(linkerServices), callType);
|
||||
// drop callee (Undefined ScriptFunction) and change the request to be dyn:callMethod:<name>
|
||||
final NashornCallSiteDescriptor newDesc = NashornCallSiteDescriptor.get(desc.getLookup(),
|
||||
"dyn:callMethod:" + name, desc.getMethodType().dropParameterTypes(1, 2),
|
||||
NashornCallSiteDescriptor.getFlags(desc));
|
||||
final GuardedInvocation gi = getGuardedInvocation(beansLinker,
|
||||
linkRequest.replaceArguments(newDesc, linkRequest.getArguments()),
|
||||
new NashornBeansLinkerServices(linkerServices));
|
||||
|
||||
// drop 'thiz' passed from the script.
|
||||
return gi.replaceMethods(
|
||||
MH.dropArguments(linkerServices.filterInternalObjects(gi.getInvocation()), 1, callType.parameterType(1)),
|
||||
gi.getGuard());
|
||||
}
|
||||
}
|
||||
return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
|
||||
@ -163,7 +165,7 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
return arg instanceof ConsString ? arg.toString() : arg;
|
||||
}
|
||||
|
||||
private static Method findFunctionalInterfaceMethod(final Class<?> clazz) {
|
||||
private static String findFunctionalInterfaceMethodName(final Class<?> clazz) {
|
||||
if (clazz == null) {
|
||||
return null;
|
||||
}
|
||||
@ -179,20 +181,20 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
// return the first abstract method
|
||||
for (final Method m : iface.getMethods()) {
|
||||
if (Modifier.isAbstract(m.getModifiers())) {
|
||||
return m;
|
||||
return m.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// did not find here, try super class
|
||||
return findFunctionalInterfaceMethod(clazz.getSuperclass());
|
||||
return findFunctionalInterfaceMethodName(clazz.getSuperclass());
|
||||
}
|
||||
|
||||
// Returns @FunctionalInterface annotated interface's single abstract
|
||||
// method. If not found, returns null.
|
||||
static Method getFunctionalInterfaceMethod(final Class<?> clazz) {
|
||||
return FUNCTIONAL_IFACE_METHOD.get(clazz);
|
||||
// method name. If not found, returns null.
|
||||
static String getFunctionalInterfaceMethodName(final Class<?> clazz) {
|
||||
return FUNCTIONAL_IFACE_METHOD_NAME.get(clazz);
|
||||
}
|
||||
|
||||
static MethodHandleTransformer createHiddenObjectFilter() {
|
||||
|
49
nashorn/test/script/basic/JDK-8068901.js
Normal file
49
nashorn/test/script/basic/JDK-8068901.js
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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-8068901: Surprising behavior with more than one functional interface on a class
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var Consumer = java.util.function.Consumer;
|
||||
var JFunction = java.util.function.Function;
|
||||
|
||||
var fc = new (Java.extend(JFunction, Consumer))({
|
||||
apply: function(x) { print("fc invoked as a function") },
|
||||
accept: function(x) { print("fc invoked as a consumer") }
|
||||
});
|
||||
|
||||
var c = new Consumer(function(x) { print("c invoked as a consumer") });
|
||||
|
||||
var cf = new (Java.extend(Consumer, JFunction))({
|
||||
apply: function(x) { print("cf invoked as a function") },
|
||||
accept: function(x) { print("cf invoked as a consumer") }
|
||||
});
|
||||
|
||||
var f = new JFunction(function(x) { print("f invoked as a function") });
|
||||
|
||||
for each(x in [fc, c, fc, cf, f, cf, c, fc, f, cf]) { x(null); }
|
||||
|
10
nashorn/test/script/basic/JDK-8068901.js.EXPECTED
Normal file
10
nashorn/test/script/basic/JDK-8068901.js.EXPECTED
Normal file
@ -0,0 +1,10 @@
|
||||
fc invoked as a function
|
||||
c invoked as a consumer
|
||||
fc invoked as a function
|
||||
cf invoked as a consumer
|
||||
f invoked as a function
|
||||
cf invoked as a consumer
|
||||
c invoked as a consumer
|
||||
fc invoked as a function
|
||||
f invoked as a function
|
||||
cf invoked as a consumer
|
40
nashorn/test/script/basic/JDK-8068903.js
Normal file
40
nashorn/test/script/basic/JDK-8068903.js
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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-8068903: Can't invoke vararg @FunctionalInterface methods
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var vc = new (Java.type("jdk.nashorn.test.models.VarArgConsumer"))(
|
||||
function(x) {
|
||||
Assert.assertTrue(x.length == 3);
|
||||
Assert.assertTrue(x[0] == 1);
|
||||
Assert.assertTrue(x[1] == 2);
|
||||
Assert.assertTrue(x[2] == 3);
|
||||
}
|
||||
);
|
||||
|
||||
vc(1, 2, 3);
|
35
nashorn/test/src/jdk/nashorn/test/models/VarArgConsumer.java
Normal file
35
nashorn/test/src/jdk/nashorn/test/models/VarArgConsumer.java
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.test.models;
|
||||
|
||||
/**
|
||||
* Simple function interface with a varargs SAM method.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface VarArgConsumer {
|
||||
public void apply(Object... o);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user