diff --git a/src/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/share/classes/java/lang/invoke/MethodHandleProxies.java index d6ae44a65772091c882ccf74478cc869166f55b6..82fde2ac3c309a8b990c3187a3829ead0502eb58 100644 --- a/src/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/src/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -27,6 +27,7 @@ package java.lang.invoke; import java.lang.reflect.*; import sun.invoke.WrapperInstance; +import java.util.ArrayList; /** * This class consists exclusively of static methods that help adapt @@ -134,14 +135,19 @@ public class MethodHandleProxies { // public static T asInterfaceInstance(final Class intfc, final MethodHandle target) { - // POC implementation only; violates the above contract several ways - final Method sm = getSingleMethod(intfc); - if (sm == null) + if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) + throw new IllegalArgumentException("not a public interface: "+intfc.getName()); + final Method[] methods = getSingleNameMethods(intfc); + if (methods == null) throw new IllegalArgumentException("not a single-method interface: "+intfc.getName()); - MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes()); - MethodHandle checkTarget = target.asType(smMT); // make throw WMT - checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); - final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, smMT.parameterCount()); + final MethodHandle[] vaTargets = new MethodHandle[methods.length]; + for (int i = 0; i < methods.length; i++) { + Method sm = methods[i]; + MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes()); + MethodHandle checkTarget = target.asType(smMT); // make throw WMT + checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); + vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount()); + } return intfc.cast(Proxy.newProxyInstance( intfc.getClassLoader(), new Class[]{ intfc, WrapperInstance.class }, @@ -152,13 +158,15 @@ public class MethodHandleProxies { throw new AssertionError(); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + for (int i = 0; i < methods.length; i++) { + if (method.equals(methods[i])) + return vaTargets[i].invokeExact(args); + } if (method.getDeclaringClass() == WrapperInstance.class) return getArg(method.getName()); - if (method.equals(sm)) - return vaTarget.invokeExact(args); if (isObjectMethod(method)) return callObjectMethod(this, method, args); - throw new InternalError(); + throw new InternalError("bad proxy method: "+method); } })); } @@ -241,17 +249,20 @@ public class MethodHandleProxies { } private static - Method getSingleMethod(Class intfc) { - if (!intfc.isInterface()) return null; - Method sm = null; + Method[] getSingleNameMethods(Class intfc) { + ArrayList methods = new ArrayList(); + String uniqueName = null; for (Method m : intfc.getMethods()) { - int mod = m.getModifiers(); - if (Modifier.isAbstract(mod)) { - if (sm != null && !isObjectMethod(sm)) - return null; // too many abstract methods - sm = m; - } + if (isObjectMethod(m)) continue; + if (!Modifier.isAbstract(m.getModifiers())) continue; + String mname = m.getName(); + if (uniqueName == null) + uniqueName = mname; + else if (!uniqueName.equals(mname)) + return null; // too many abstract methods + methods.add(m); } - return sm; + if (uniqueName == null) return null; + return methods.toArray(new Method[methods.size()]); } } diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java index 1fd6a5c86c892b46f55876c201ea6465328fc6a0..8ced35bdfcdb9c1f016a1549ed0c8c17ea850ebb 100644 --- a/test/java/lang/invoke/MethodHandlesTest.java +++ b/test/java/lang/invoke/MethodHandlesTest.java @@ -2234,7 +2234,7 @@ public class MethodHandlesTest { static void runForRunnable() { called("runForRunnable"); } - private interface Fooable { + public interface Fooable { Object foo(Fooable x, Object y); // this is for randomArg: public class Impl implements Fooable { @@ -2249,9 +2249,9 @@ public class MethodHandlesTest { static Object fooForFooable(Fooable x, Object y) { return called("fooForFooable", x, y); } - private static class MyCheckedException extends Exception { + public static class MyCheckedException extends Exception { } - private interface WillThrow { + public interface WillThrow { void willThrow() throws MyCheckedException; } @@ -2300,8 +2300,11 @@ public class MethodHandlesTest { assertSame("must pass declared exception out without wrapping", ex, ex1); } else { assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1); + if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) { + ex1.printStackTrace(); + } + assertSame(ex, ex1.getCause()); UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1; - assertSame(ex, utex.getCause()); } } } @@ -2380,8 +2383,7 @@ class ValueConversions { public static MethodHandle varargsArray(int nargs) { if (nargs < ARRAYS.length) return ARRAYS[nargs]; - // else need to spin bytecode or do something else fancy - throw new UnsupportedOperationException("NYI: cannot form a varargs array of length "+nargs); + return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs); } public static MethodHandle varargsArray(Class arrayType, int nargs) { Class elemType = arrayType.getComponentType(); @@ -2463,6 +2465,12 @@ class ValueConversions { return lists.toArray(new MethodHandle[0]); } static final MethodHandle[] LISTS = makeLists(); + static final MethodHandle AS_LIST; + static { + try { + AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); + } catch (Exception ex) { throw new RuntimeException(ex); } + } /** Return a method handle that takes the indicated number of Object * arguments and returns List. @@ -2470,8 +2478,7 @@ class ValueConversions { public static MethodHandle varargsList(int nargs) { if (nargs < LISTS.length) return LISTS[nargs]; - // else need to spin bytecode or do something else fancy - throw new UnsupportedOperationException("NYI"); + return AS_LIST.asCollector(Object[].class, nargs); } } // This guy tests access from outside the same package member, but inside