提交 89470114 编写于 作者: J jrose

7054590: (JSR-292) MethodHandleProxies.asInterfaceInstance() accepts...

7054590: (JSR-292) MethodHandleProxies.asInterfaceInstance() accepts private/protected nested interfaces
Summary: fix non-compliant logic in MethodHandleProxies, fix invalid private classes in MethodHandlesTest
Reviewed-by: twisti, never
上级 33464f30
......@@ -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> T asInterfaceInstance(final Class<T> 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<Method> methods = new ArrayList<Method>();
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()]);
}
}
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册