16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import java.lang.reflect.*;
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31 import sun.invoke.WrapperInstance;
32 import java.util.ArrayList;
33 import sun.reflect.CallerSensitive;
34 import sun.reflect.Reflection;
35 import sun.reflect.misc.ReflectUtil;
36
37 /**
38 * This class consists exclusively of static methods that help adapt
39 * method handles to other JVM types, such as interfaces.
40 */
41 public class MethodHandleProxies {
42
43 private MethodHandleProxies() { } // do not instantiate
44
45 /**
46 * Produces an instance of the given single-method interface which redirects
47 * its calls to the given method handle.
48 * <p>
49 * A single-method interface is an interface which declares a uniquely named method.
50 * When determining the uniquely named method of a single-method interface,
51 * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
52 * are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
53 * even though it re-declares the {@code Object.equals} method.
54 * <p>
55 * The interface must be public. No additional access checks are performed.
131 // <p>
132 // If the implementation is able
133 // to prove that a wrapper of the required type
134 // has already been created for a given
135 // method handle, or for another method handle with the
136 // same behavior, the implementation may return that wrapper in place of
137 // a new wrapper.
138 // <p>
139 // This method is designed to apply to common use cases
140 // where a single method handle must interoperate with
141 // an interface that implements a function-like
142 // API. Additional variations, such as single-abstract-method classes with
143 // private constructors, or interfaces with multiple but related
144 // entry points, must be covered by hand-written or automatically
145 // generated adapter classes.
146 //
147 @CallerSensitive
148 public static
149 <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
150 if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
151 throw new IllegalArgumentException("not a public interface: "+intfc.getName());
152 final MethodHandle mh;
153 if (System.getSecurityManager() != null) {
154 final Class<?> caller = Reflection.getCallerClass();
155 final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
156 ReflectUtil.checkProxyPackageAccess(ccl, intfc);
157 mh = ccl != null ? bindCaller(target, caller) : target;
158 } else {
159 mh = target;
160 }
161 ClassLoader proxyLoader = intfc.getClassLoader();
162 if (proxyLoader == null) {
163 ClassLoader cl = Thread.currentThread().getContextClassLoader(); // avoid use of BCP
164 proxyLoader = cl != null ? cl : ClassLoader.getSystemClassLoader();
165 }
166 final Method[] methods = getSingleNameMethods(intfc);
167 if (methods == null)
168 throw new IllegalArgumentException("not a single-method interface: "+intfc.getName());
169 final MethodHandle[] vaTargets = new MethodHandle[methods.length];
170 for (int i = 0; i < methods.length; i++) {
171 Method sm = methods[i];
172 MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
173 MethodHandle checkTarget = mh.asType(smMT); // make throw WMT
174 checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
175 vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
176 }
177 final InvocationHandler ih = new InvocationHandler() {
178 private Object getArg(String name) {
179 if ((Object)name == "getWrapperInstanceTarget") return target;
180 if ((Object)name == "getWrapperInstanceType") return intfc;
181 throw new AssertionError();
182 }
183 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
184 for (int i = 0; i < methods.length; i++) {
185 if (method.equals(methods[i]))
186 return vaTargets[i].invokeExact(args);
187 }
188 if (method.getDeclaringClass() == WrapperInstance.class)
189 return getArg(method.getName());
190 if (isObjectMethod(method))
191 return callObjectMethod(proxy, method, args);
192 throw new InternalError("bad proxy method: "+method);
193 }
194 };
195
196 final Object proxy;
197 if (System.getSecurityManager() != null) {
198 // sun.invoke.WrapperInstance is a restricted interface not accessible
199 // by any non-null class loader.
200 final ClassLoader loader = proxyLoader;
201 proxy = AccessController.doPrivileged(new PrivilegedAction<Object>() {
202 public Object run() {
203 return Proxy.newProxyInstance(
204 loader,
205 new Class<?>[]{ intfc, WrapperInstance.class },
206 ih);
207 }
208 });
209 } else {
210 proxy = Proxy.newProxyInstance(proxyLoader,
211 new Class<?>[]{ intfc, WrapperInstance.class },
212 ih);
223 }
224 return cbmh;
225 }
226
227 /**
228 * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
229 * @param x any reference
230 * @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance}
231 */
232 public static
233 boolean isWrapperInstance(Object x) {
234 return x instanceof WrapperInstance;
235 }
236
237 private static WrapperInstance asWrapperInstance(Object x) {
238 try {
239 if (x != null)
240 return (WrapperInstance) x;
241 } catch (ClassCastException ex) {
242 }
243 throw new IllegalArgumentException("not a wrapper instance");
244 }
245
246 /**
247 * Produces or recovers a target method handle which is behaviorally
248 * equivalent to the unique method of this wrapper instance.
249 * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
250 * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
251 * @param x any reference
252 * @return a method handle implementing the unique method
253 * @throws IllegalArgumentException if the reference x is not to a wrapper instance
254 */
255 public static
256 MethodHandle wrapperInstanceTarget(Object x) {
257 return asWrapperInstance(x).getWrapperInstanceTarget();
258 }
259
260 /**
261 * Recovers the unique single-method interface type for which this wrapper instance was created.
262 * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
263 * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
|
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import java.lang.reflect.*;
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31 import sun.invoke.WrapperInstance;
32 import java.util.ArrayList;
33 import sun.reflect.CallerSensitive;
34 import sun.reflect.Reflection;
35 import sun.reflect.misc.ReflectUtil;
36 import static java.lang.invoke.MethodHandleStatics.*;
37
38 /**
39 * This class consists exclusively of static methods that help adapt
40 * method handles to other JVM types, such as interfaces.
41 */
42 public class MethodHandleProxies {
43
44 private MethodHandleProxies() { } // do not instantiate
45
46 /**
47 * Produces an instance of the given single-method interface which redirects
48 * its calls to the given method handle.
49 * <p>
50 * A single-method interface is an interface which declares a uniquely named method.
51 * When determining the uniquely named method of a single-method interface,
52 * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
53 * are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
54 * even though it re-declares the {@code Object.equals} method.
55 * <p>
56 * The interface must be public. No additional access checks are performed.
132 // <p>
133 // If the implementation is able
134 // to prove that a wrapper of the required type
135 // has already been created for a given
136 // method handle, or for another method handle with the
137 // same behavior, the implementation may return that wrapper in place of
138 // a new wrapper.
139 // <p>
140 // This method is designed to apply to common use cases
141 // where a single method handle must interoperate with
142 // an interface that implements a function-like
143 // API. Additional variations, such as single-abstract-method classes with
144 // private constructors, or interfaces with multiple but related
145 // entry points, must be covered by hand-written or automatically
146 // generated adapter classes.
147 //
148 @CallerSensitive
149 public static
150 <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
151 if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
152 throw newIllegalArgumentException("not a public interface", intfc.getName());
153 final MethodHandle mh;
154 if (System.getSecurityManager() != null) {
155 final Class<?> caller = Reflection.getCallerClass();
156 final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
157 ReflectUtil.checkProxyPackageAccess(ccl, intfc);
158 mh = ccl != null ? bindCaller(target, caller) : target;
159 } else {
160 mh = target;
161 }
162 ClassLoader proxyLoader = intfc.getClassLoader();
163 if (proxyLoader == null) {
164 ClassLoader cl = Thread.currentThread().getContextClassLoader(); // avoid use of BCP
165 proxyLoader = cl != null ? cl : ClassLoader.getSystemClassLoader();
166 }
167 final Method[] methods = getSingleNameMethods(intfc);
168 if (methods == null)
169 throw newIllegalArgumentException("not a single-method interface", intfc.getName());
170 final MethodHandle[] vaTargets = new MethodHandle[methods.length];
171 for (int i = 0; i < methods.length; i++) {
172 Method sm = methods[i];
173 MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
174 MethodHandle checkTarget = mh.asType(smMT); // make throw WMT
175 checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
176 vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
177 }
178 final InvocationHandler ih = new InvocationHandler() {
179 private Object getArg(String name) {
180 if ((Object)name == "getWrapperInstanceTarget") return target;
181 if ((Object)name == "getWrapperInstanceType") return intfc;
182 throw new AssertionError();
183 }
184 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
185 for (int i = 0; i < methods.length; i++) {
186 if (method.equals(methods[i]))
187 return vaTargets[i].invokeExact(args);
188 }
189 if (method.getDeclaringClass() == WrapperInstance.class)
190 return getArg(method.getName());
191 if (isObjectMethod(method))
192 return callObjectMethod(proxy, method, args);
193 throw newInternalError("bad proxy method: "+method);
194 }
195 };
196
197 final Object proxy;
198 if (System.getSecurityManager() != null) {
199 // sun.invoke.WrapperInstance is a restricted interface not accessible
200 // by any non-null class loader.
201 final ClassLoader loader = proxyLoader;
202 proxy = AccessController.doPrivileged(new PrivilegedAction<Object>() {
203 public Object run() {
204 return Proxy.newProxyInstance(
205 loader,
206 new Class<?>[]{ intfc, WrapperInstance.class },
207 ih);
208 }
209 });
210 } else {
211 proxy = Proxy.newProxyInstance(proxyLoader,
212 new Class<?>[]{ intfc, WrapperInstance.class },
213 ih);
224 }
225 return cbmh;
226 }
227
228 /**
229 * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
230 * @param x any reference
231 * @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance}
232 */
233 public static
234 boolean isWrapperInstance(Object x) {
235 return x instanceof WrapperInstance;
236 }
237
238 private static WrapperInstance asWrapperInstance(Object x) {
239 try {
240 if (x != null)
241 return (WrapperInstance) x;
242 } catch (ClassCastException ex) {
243 }
244 throw newIllegalArgumentException("not a wrapper instance");
245 }
246
247 /**
248 * Produces or recovers a target method handle which is behaviorally
249 * equivalent to the unique method of this wrapper instance.
250 * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
251 * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
252 * @param x any reference
253 * @return a method handle implementing the unique method
254 * @throws IllegalArgumentException if the reference x is not to a wrapper instance
255 */
256 public static
257 MethodHandle wrapperInstanceTarget(Object x) {
258 return asWrapperInstance(x).getWrapperInstanceTarget();
259 }
260
261 /**
262 * Recovers the unique single-method interface type for which this wrapper instance was created.
263 * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
264 * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
|