-
Bug
-
Resolution: Fixed
-
P4
-
11, 17, 18, 19
-
b07
-
generic
-
generic
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8329495 | 17.0.12 | Severin Gehwolf | P4 | Resolved | Fixed | b01 |
A DESCRIPTION OF THE PROBLEM :
When creating an interface proxy to a MethodHandle using MethodHandleProxies.asInterfaceInstance, default methods using a varargs parameter are not correctly handled.
Calling such a default method on a MethodHandle proxy will produce an IllegalArgumentException with message "array is not of length X", as the method handles are not correctly combined. Default methods with a regular array as their trailing parameter are not affected.
The cause of this issue is that MethodHandleProxies.callDefaultMethod does not ensure that the MethodHandle obtained for the default method is not a varargs collector (MethodHandle.isVarargsCollector). If it is, it will try to collect varargs arguments, instead of passing the array on "as is". The vararg argument collection has already happened at this point, because the generated java.lang.reflect.Proxy code has no special handling of varargs, it treats them as regular arrays. The fix is that callDefaultMethod needs to call asFixedArity on the result of findSpecial.
---------- BEGIN SOURCE ----------
package com.example;
import java.lang.invoke.MethodHandleProxies;
import java.lang.invoke.MethodHandles;
import static java.lang.invoke.MethodType.methodType;
public class Main {
public interface Interface
{
void method(Object... args);
default void defaultMethod(Object... args) {
method(args);
}
default void defaultMethod2(Object[] args) {
method(args);
}
}
private static void callMeViaMethodHandles(String foo, int bar) {
System.out.println("foo=" + foo + ", bar=" + bar);
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException
{
var mh = MethodHandles.lookup().findStatic(
Main.class, "callMeViaMethodHandles", methodType(void.class, String.class, int.class)
);
mh = mh.asSpreader(Object[].class, mh.type().parameterCount());
var proxy = MethodHandleProxies.asInterfaceInstance(Interface.class, mh);
// throws incorrect exception
proxy.defaultMethod("should be foo", 3);
// works fine
proxy.defaultMethod2(new Object[] { "should be foo", 3 });
}
}
---------- END SOURCE ----------
FREQUENCY : always
When creating an interface proxy to a MethodHandle using MethodHandleProxies.asInterfaceInstance, default methods using a varargs parameter are not correctly handled.
Calling such a default method on a MethodHandle proxy will produce an IllegalArgumentException with message "array is not of length X", as the method handles are not correctly combined. Default methods with a regular array as their trailing parameter are not affected.
The cause of this issue is that MethodHandleProxies.callDefaultMethod does not ensure that the MethodHandle obtained for the default method is not a varargs collector (MethodHandle.isVarargsCollector). If it is, it will try to collect varargs arguments, instead of passing the array on "as is". The vararg argument collection has already happened at this point, because the generated java.lang.reflect.Proxy code has no special handling of varargs, it treats them as regular arrays. The fix is that callDefaultMethod needs to call asFixedArity on the result of findSpecial.
---------- BEGIN SOURCE ----------
package com.example;
import java.lang.invoke.MethodHandleProxies;
import java.lang.invoke.MethodHandles;
import static java.lang.invoke.MethodType.methodType;
public class Main {
public interface Interface
{
void method(Object... args);
default void defaultMethod(Object... args) {
method(args);
}
default void defaultMethod2(Object[] args) {
method(args);
}
}
private static void callMeViaMethodHandles(String foo, int bar) {
System.out.println("foo=" + foo + ", bar=" + bar);
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException
{
var mh = MethodHandles.lookup().findStatic(
Main.class, "callMeViaMethodHandles", methodType(void.class, String.class, int.class)
);
mh = mh.asSpreader(Object[].class, mh.type().parameterCount());
var proxy = MethodHandleProxies.asInterfaceInstance(Interface.class, mh);
// throws incorrect exception
proxy.defaultMethod("should be foo", 3);
// works fine
proxy.defaultMethod2(new Object[] { "should be foo", 3 });
}
}
---------- END SOURCE ----------
FREQUENCY : always
- backported by
-
JDK-8329495 MethodHandleProxies does not correctly invoke default methods with varags
- Resolved