diff -r eca8e9c3ec3e -r cd50c1894ce5 rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleProxies.java --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleProxies.java Sun Aug 17 20:09:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,321 +0,0 @@ -/* - * Copyright (c) 2008, 2013, 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 java.lang.invoke; - -import java.lang.reflect.*; -import java.security.AccessController; -import java.security.PrivilegedAction; -import sun.invoke.WrapperInstance; -import java.util.ArrayList; -//import sun.reflect.CallerSensitive; -//import sun.reflect.Reflection; -//import sun.reflect.misc.ReflectUtil; - -/** - * This class consists exclusively of static methods that help adapt - * method handles to other JVM types, such as interfaces. - */ -public class MethodHandleProxies { - - private MethodHandleProxies() { } // do not instantiate - - /** - * Produces an instance of the given single-method interface which redirects - * its calls to the given method handle. - *

- * A single-method interface is an interface which declares a uniquely named method. - * When determining the uniquely named method of a single-method interface, - * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode}) - * are disregarded. For example, {@link java.util.Comparator} is a single-method interface, - * even though it re-declares the {@code Object.equals} method. - *

- * The interface must be public. No additional access checks are performed. - *

- * The resulting instance of the required type will respond to - * invocation of the type's uniquely named method by calling - * the given target on the incoming arguments, - * and returning or throwing whatever the target - * returns or throws. The invocation will be as if by - * {@code target.invoke}. - * The target's type will be checked before the - * instance is created, as if by a call to {@code asType}, - * which may result in a {@code WrongMethodTypeException}. - *

- * The uniquely named method is allowed to be multiply declared, - * with distinct type descriptors. (E.g., it can be overloaded, - * or can possess bridge methods.) All such declarations are - * connected directly to the target method handle. - * Argument and return types are adjusted by {@code asType} - * for each individual declaration. - *

- * The wrapper instance will implement the requested interface - * and its super-types, but no other single-method interfaces. - * This means that the instance will not unexpectedly - * pass an {@code instanceof} test for any unrequested type. - *

- * Implementation Note: - * Therefore, each instance must implement a unique single-method interface. - * Implementations may not bundle together - * multiple single-method interfaces onto single implementation classes - * in the style of {@link java.awt.AWTEventMulticaster}. - *

- * The method handle may throw an undeclared exception, - * which means any checked exception (or other checked throwable) - * not declared by the requested type's single abstract method. - * If this happens, the throwable will be wrapped in an instance of - * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException} - * and thrown in that wrapped form. - *

- * Like {@link java.lang.Integer#valueOf Integer.valueOf}, - * {@code asInterfaceInstance} is a factory method whose results are defined - * by their behavior. - * It is not guaranteed to return a new instance for every call. - *

- * Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods} - * and other corner cases, the interface may also have several abstract methods - * with the same name but having distinct descriptors (types of returns and parameters). - * In this case, all the methods are bound in common to the one given target. - * The type check and effective {@code asType} conversion is applied to each - * method type descriptor, and all abstract methods are bound to the target in common. - * Beyond this type check, no further checks are made to determine that the - * abstract methods are related in any way. - *

- * Future versions of this API may accept additional types, - * such as abstract classes with single abstract methods. - * Future versions of this API may also equip wrapper instances - * with one or more additional public "marker" interfaces. - *

- * If a security manager is installed, this method is caller sensitive. - * During any invocation of the target method handle via the returned wrapper, - * the original creator of the wrapper (the caller) will be visible - * to context checks requested by the security manager. - * - * @param the desired type of the wrapper, a single-method interface - * @param intfc a class object representing {@code T} - * @param target the method handle to invoke from the wrapper - * @return a correctly-typed wrapper for the given target - * @throws NullPointerException if either argument is null - * @throws IllegalArgumentException if the {@code intfc} is not a - * valid argument to this method - * @throws WrongMethodTypeException if the target cannot - * be converted to the type required by the requested interface - */ - // Other notes to implementors: - //

- // No stable mapping is promised between the single-method interface and - // the implementation class C. Over time, several implementation - // classes might be used for the same type. - //

- // If the implementation is able - // to prove that a wrapper of the required type - // has already been created for a given - // method handle, or for another method handle with the - // same behavior, the implementation may return that wrapper in place of - // a new wrapper. - //

- // This method is designed to apply to common use cases - // where a single method handle must interoperate with - // an interface that implements a function-like - // API. Additional variations, such as single-abstract-method classes with - // private constructors, or interfaces with multiple but related - // entry points, must be covered by hand-written or automatically - // generated adapter classes. - // -// @CallerSensitive - public static - T asInterfaceInstance(final Class intfc, final MethodHandle target) { - if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) - throw new IllegalArgumentException("not a public interface: "+intfc.getName()); - final MethodHandle mh; - if (false) {//System.getSecurityManager() != null) { -// final Class caller = Reflection.getCallerClass(); -// final ClassLoader ccl = caller != null ? caller.getClassLoader() : null; -// ReflectUtil.checkProxyPackageAccess(ccl, intfc); -// mh = ccl != null ? bindCaller(target, caller) : target; - } else { - mh = target; - } - ClassLoader proxyLoader = intfc.getClassLoader(); - if (proxyLoader == null) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); // avoid use of BCP - proxyLoader = cl != null ? cl : ClassLoader.getSystemClassLoader(); - } - final Method[] methods = getSingleNameMethods(intfc); - if (methods == null) - throw new IllegalArgumentException("not a single-method interface: "+intfc.getName()); - 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 = mh.asType(smMT); // make throw WMT - checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); - vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount()); - } - final InvocationHandler ih = new InvocationHandler() { - private Object getArg(String name) { - if ((Object)name == "getWrapperInstanceTarget") return target; - if ((Object)name == "getWrapperInstanceType") return intfc; - 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 (isObjectMethod(method)) - return callObjectMethod(proxy, method, args); - throw new InternalError("bad proxy method: "+method); - } - }; - - final Object proxy; - if (false) { // System.getSecurityManager() != null) { - // sun.invoke.WrapperInstance is a restricted interface not accessible - // by any non-null class loader. - final ClassLoader loader = proxyLoader; - proxy = AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return Proxy.newProxyInstance( - loader, - new Class[]{ intfc, WrapperInstance.class }, - ih); - } - }); - } else { - proxy = Proxy.newProxyInstance(proxyLoader, - new Class[]{ intfc, WrapperInstance.class }, - ih); - } - return intfc.cast(proxy); - } - - private static MethodHandle bindCaller(MethodHandle target, Class hostClass) { - MethodHandle cbmh = MethodHandleImpl.bindCaller(target, hostClass); - if (target.isVarargsCollector()) { - MethodType type = cbmh.type(); - int arity = type.parameterCount(); - return cbmh.asVarargsCollector(type.parameterType(arity-1)); - } - return cbmh; - } - - /** - * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}. - * @param x any reference - * @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance} - */ - public static - boolean isWrapperInstance(Object x) { - return x instanceof WrapperInstance; - } - - private static WrapperInstance asWrapperInstance(Object x) { - try { - if (x != null) - return (WrapperInstance) x; - } catch (ClassCastException ex) { - } - throw new IllegalArgumentException("not a wrapper instance"); - } - - /** - * Produces or recovers a target method handle which is behaviorally - * equivalent to the unique method of this wrapper instance. - * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}. - * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}. - * @param x any reference - * @return a method handle implementing the unique method - * @throws IllegalArgumentException if the reference x is not to a wrapper instance - */ - public static - MethodHandle wrapperInstanceTarget(Object x) { - return asWrapperInstance(x).getWrapperInstanceTarget(); - } - - /** - * Recovers the unique single-method interface type for which this wrapper instance was created. - * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}. - * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}. - * @param x any reference - * @return the single-method interface type for which the wrapper was created - * @throws IllegalArgumentException if the reference x is not to a wrapper instance - */ - public static - Class wrapperInstanceType(Object x) { - return asWrapperInstance(x).getWrapperInstanceType(); - } - - private static - boolean isObjectMethod(Method m) { - switch (m.getName()) { - case "toString": - return (m.getReturnType() == String.class - && m.getParameterTypes().length == 0); - case "hashCode": - return (m.getReturnType() == int.class - && m.getParameterTypes().length == 0); - case "equals": - return (m.getReturnType() == boolean.class - && m.getParameterTypes().length == 1 - && m.getParameterTypes()[0] == Object.class); - } - return false; - } - - private static - Object callObjectMethod(Object self, Method m, Object[] args) { - assert(isObjectMethod(m)) : m; - switch (m.getName()) { - case "toString": - return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode()); - case "hashCode": - return System.identityHashCode(self); - case "equals": - return (self == args[0]); - } - return null; - } - - private static - Method[] getSingleNameMethods(Class intfc) { - ArrayList methods = new ArrayList(); - String uniqueName = null; - for (Method m : intfc.getMethods()) { - 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); - } - if (uniqueName == null) return null; - return methods.toArray(new Method[methods.size()]); - } -}