1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java Mon Oct 21 14:34:12 2013 +0200
1.3 @@ -0,0 +1,1620 @@
1.4 +/*
1.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +package org.apidesign.bck2brwsr.emul.reflect;
1.30 +
1.31 +import java.io.ByteArrayOutputStream;
1.32 +import java.io.DataOutputStream;
1.33 +import java.io.IOException;
1.34 +import java.io.OutputStream;
1.35 +import java.lang.ref.Reference;
1.36 +import java.lang.ref.WeakReference;
1.37 +import java.lang.reflect.Array;
1.38 +import java.lang.reflect.Constructor;
1.39 +import java.lang.reflect.InvocationHandler;
1.40 +import java.lang.reflect.InvocationTargetException;
1.41 +import java.lang.reflect.Method;
1.42 +import java.lang.reflect.Modifier;
1.43 +import java.util.ArrayList;
1.44 +import java.util.Arrays;
1.45 +import java.util.Collections;
1.46 +import java.util.HashMap;
1.47 +import java.util.HashSet;
1.48 +import java.util.LinkedList;
1.49 +import java.util.Map;
1.50 +import java.util.Set;
1.51 +import java.util.List;
1.52 +import java.util.ListIterator;
1.53 +import java.util.WeakHashMap;
1.54 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
1.55 +import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
1.56 +
1.57 +/**
1.58 + * {@code Proxy} provides static methods for creating dynamic proxy
1.59 + * classes and instances, and it is also the superclass of all
1.60 + * dynamic proxy classes created by those methods.
1.61 + *
1.62 + * <p>To create a proxy for some interface {@code Foo}:
1.63 + * <pre>
1.64 + * InvocationHandler handler = new MyInvocationHandler(...);
1.65 + * Class proxyClass = Proxy.getProxyClass(
1.66 + * Foo.class.getClassLoader(), new Class[] { Foo.class });
1.67 + * Foo f = (Foo) proxyClass.
1.68 + * getConstructor(new Class[] { InvocationHandler.class }).
1.69 + * newInstance(new Object[] { handler });
1.70 + * </pre>
1.71 + * or more simply:
1.72 + * <pre>
1.73 + * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
1.74 + * new Class[] { Foo.class },
1.75 + * handler);
1.76 + * </pre>
1.77 + *
1.78 + * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
1.79 + * class</i> below) is a class that implements a list of interfaces
1.80 + * specified at runtime when the class is created, with behavior as
1.81 + * described below.
1.82 + *
1.83 + * A <i>proxy interface</i> is such an interface that is implemented
1.84 + * by a proxy class.
1.85 + *
1.86 + * A <i>proxy instance</i> is an instance of a proxy class.
1.87 + *
1.88 + * Each proxy instance has an associated <i>invocation handler</i>
1.89 + * object, which implements the interface {@link InvocationHandler}.
1.90 + * A method invocation on a proxy instance through one of its proxy
1.91 + * interfaces will be dispatched to the {@link InvocationHandler#invoke
1.92 + * invoke} method of the instance's invocation handler, passing the proxy
1.93 + * instance, a {@code java.lang.reflect.Method} object identifying
1.94 + * the method that was invoked, and an array of type {@code Object}
1.95 + * containing the arguments. The invocation handler processes the
1.96 + * encoded method invocation as appropriate and the result that it
1.97 + * returns will be returned as the result of the method invocation on
1.98 + * the proxy instance.
1.99 + *
1.100 + * <p>A proxy class has the following properties:
1.101 + *
1.102 + * <ul>
1.103 + * <li>Proxy classes are public, final, and not abstract.
1.104 + *
1.105 + * <li>The unqualified name of a proxy class is unspecified. The space
1.106 + * of class names that begin with the string {@code "$Proxy"}
1.107 + * should be, however, reserved for proxy classes.
1.108 + *
1.109 + * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
1.110 + *
1.111 + * <li>A proxy class implements exactly the interfaces specified at its
1.112 + * creation, in the same order.
1.113 + *
1.114 + * <li>If a proxy class implements a non-public interface, then it will
1.115 + * be defined in the same package as that interface. Otherwise, the
1.116 + * package of a proxy class is also unspecified. Note that package
1.117 + * sealing will not prevent a proxy class from being successfully defined
1.118 + * in a particular package at runtime, and neither will classes already
1.119 + * defined by the same class loader and the same package with particular
1.120 + * signers.
1.121 + *
1.122 + * <li>Since a proxy class implements all of the interfaces specified at
1.123 + * its creation, invoking {@code getInterfaces} on its
1.124 + * {@code Class} object will return an array containing the same
1.125 + * list of interfaces (in the order specified at its creation), invoking
1.126 + * {@code getMethods} on its {@code Class} object will return
1.127 + * an array of {@code Method} objects that include all of the
1.128 + * methods in those interfaces, and invoking {@code getMethod} will
1.129 + * find methods in the proxy interfaces as would be expected.
1.130 + *
1.131 + * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
1.132 + * return true if it is passed a proxy class-- a class returned by
1.133 + * {@code Proxy.getProxyClass} or the class of an object returned by
1.134 + * {@code Proxy.newProxyInstance}-- and false otherwise.
1.135 + *
1.136 + * <li>The {@code java.security.ProtectionDomain} of a proxy class
1.137 + * is the same as that of system classes loaded by the bootstrap class
1.138 + * loader, such as {@code java.lang.Object}, because the code for a
1.139 + * proxy class is generated by trusted system code. This protection
1.140 + * domain will typically be granted
1.141 + * {@code java.security.AllPermission}.
1.142 + *
1.143 + * <li>Each proxy class has one public constructor that takes one argument,
1.144 + * an implementation of the interface {@link InvocationHandler}, to set
1.145 + * the invocation handler for a proxy instance. Rather than having to use
1.146 + * the reflection API to access the public constructor, a proxy instance
1.147 + * can be also be created by calling the {@link Proxy#newProxyInstance
1.148 + * Proxy.newProxyInstance} method, which combines the actions of calling
1.149 + * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
1.150 + * constructor with an invocation handler.
1.151 + * </ul>
1.152 + *
1.153 + * <p>A proxy instance has the following properties:
1.154 + *
1.155 + * <ul>
1.156 + * <li>Given a proxy instance {@code proxy} and one of the
1.157 + * interfaces implemented by its proxy class {@code Foo}, the
1.158 + * following expression will return true:
1.159 + * <pre>
1.160 + * {@code proxy instanceof Foo}
1.161 + * </pre>
1.162 + * and the following cast operation will succeed (rather than throwing
1.163 + * a {@code ClassCastException}):
1.164 + * <pre>
1.165 + * {@code (Foo) proxy}
1.166 + * </pre>
1.167 + *
1.168 + * <li>Each proxy instance has an associated invocation handler, the one
1.169 + * that was passed to its constructor. The static
1.170 + * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method
1.171 + * will return the invocation handler associated with the proxy instance
1.172 + * passed as its argument.
1.173 + *
1.174 + * <li>An interface method invocation on a proxy instance will be
1.175 + * encoded and dispatched to the invocation handler's {@link
1.176 + * InvocationHandler#invoke invoke} method as described in the
1.177 + * documentation for that method.
1.178 + *
1.179 + * <li>An invocation of the {@code hashCode},
1.180 + * {@code equals}, or {@code toString} methods declared in
1.181 + * {@code java.lang.Object} on a proxy instance will be encoded and
1.182 + * dispatched to the invocation handler's {@code invoke} method in
1.183 + * the same manner as interface method invocations are encoded and
1.184 + * dispatched, as described above. The declaring class of the
1.185 + * {@code Method} object passed to {@code invoke} will be
1.186 + * {@code java.lang.Object}. Other public methods of a proxy
1.187 + * instance inherited from {@code java.lang.Object} are not
1.188 + * overridden by a proxy class, so invocations of those methods behave
1.189 + * like they do for instances of {@code java.lang.Object}.
1.190 + * </ul>
1.191 + *
1.192 + * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
1.193 + *
1.194 + * <p>When two or more interfaces of a proxy class contain a method with
1.195 + * the same name and parameter signature, the order of the proxy class's
1.196 + * interfaces becomes significant. When such a <i>duplicate method</i>
1.197 + * is invoked on a proxy instance, the {@code Method} object passed
1.198 + * to the invocation handler will not necessarily be the one whose
1.199 + * declaring class is assignable from the reference type of the interface
1.200 + * that the proxy's method was invoked through. This limitation exists
1.201 + * because the corresponding method implementation in the generated proxy
1.202 + * class cannot determine which interface it was invoked through.
1.203 + * Therefore, when a duplicate method is invoked on a proxy instance,
1.204 + * the {@code Method} object for the method in the foremost interface
1.205 + * that contains the method (either directly or inherited through a
1.206 + * superinterface) in the proxy class's list of interfaces is passed to
1.207 + * the invocation handler's {@code invoke} method, regardless of the
1.208 + * reference type through which the method invocation occurred.
1.209 + *
1.210 + * <p>If a proxy interface contains a method with the same name and
1.211 + * parameter signature as the {@code hashCode}, {@code equals},
1.212 + * or {@code toString} methods of {@code java.lang.Object},
1.213 + * when such a method is invoked on a proxy instance, the
1.214 + * {@code Method} object passed to the invocation handler will have
1.215 + * {@code java.lang.Object} as its declaring class. In other words,
1.216 + * the public, non-final methods of {@code java.lang.Object}
1.217 + * logically precede all of the proxy interfaces for the determination of
1.218 + * which {@code Method} object to pass to the invocation handler.
1.219 + *
1.220 + * <p>Note also that when a duplicate method is dispatched to an
1.221 + * invocation handler, the {@code invoke} method may only throw
1.222 + * checked exception types that are assignable to one of the exception
1.223 + * types in the {@code throws} clause of the method in <i>all</i> of
1.224 + * the proxy interfaces that it can be invoked through. If the
1.225 + * {@code invoke} method throws a checked exception that is not
1.226 + * assignable to any of the exception types declared by the method in one
1.227 + * of the proxy interfaces that it can be invoked through, then an
1.228 + * unchecked {@code UndeclaredThrowableException} will be thrown by
1.229 + * the invocation on the proxy instance. This restriction means that not
1.230 + * all of the exception types returned by invoking
1.231 + * {@code getExceptionTypes} on the {@code Method} object
1.232 + * passed to the {@code invoke} method can necessarily be thrown
1.233 + * successfully by the {@code invoke} method.
1.234 + *
1.235 + * @author Peter Jones
1.236 + * @see InvocationHandler
1.237 + * @since 1.3
1.238 + */
1.239 +public final class ProxyImpl implements java.io.Serializable {
1.240 +
1.241 + private static final long serialVersionUID = -2222568056686623797L;
1.242 +
1.243 + /** prefix for all proxy class names */
1.244 + private final static String proxyClassNamePrefix = "$Proxy";
1.245 +
1.246 + /** parameter types of a proxy class constructor */
1.247 + private final static Class[] constructorParams =
1.248 + { InvocationHandler.class };
1.249 +
1.250 + /** maps a class loader to the proxy class cache for that loader */
1.251 + private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
1.252 + = new WeakHashMap<>();
1.253 +
1.254 + /** marks that a particular proxy class is currently being generated */
1.255 + private static Object pendingGenerationMarker = new Object();
1.256 +
1.257 + /** next number to use for generation of unique proxy class names */
1.258 + private static long nextUniqueNumber = 0;
1.259 + private static Object nextUniqueNumberLock = new Object();
1.260 +
1.261 + /** set of all generated proxy classes, for isProxyClass implementation */
1.262 + private static Map<Class<?>, Void> proxyClasses =
1.263 + Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
1.264 +
1.265 + /**
1.266 + * the invocation handler for this proxy instance.
1.267 + * @serial
1.268 + */
1.269 + protected InvocationHandler h;
1.270 +
1.271 + /**
1.272 + * Prohibits instantiation.
1.273 + */
1.274 + private ProxyImpl() {
1.275 + }
1.276 +
1.277 + /**
1.278 + * Constructs a new {@code Proxy} instance from a subclass
1.279 + * (typically, a dynamic proxy class) with the specified value
1.280 + * for its invocation handler.
1.281 + *
1.282 + * @param h the invocation handler for this proxy instance
1.283 + */
1.284 + protected ProxyImpl(InvocationHandler h) {
1.285 + this.h = h;
1.286 + }
1.287 +
1.288 + /**
1.289 + * Returns the {@code java.lang.Class} object for a proxy class
1.290 + * given a class loader and an array of interfaces. The proxy class
1.291 + * will be defined by the specified class loader and will implement
1.292 + * all of the supplied interfaces. If a proxy class for the same
1.293 + * permutation of interfaces has already been defined by the class
1.294 + * loader, then the existing proxy class will be returned; otherwise,
1.295 + * a proxy class for those interfaces will be generated dynamically
1.296 + * and defined by the class loader.
1.297 + *
1.298 + * <p>There are several restrictions on the parameters that may be
1.299 + * passed to {@code Proxy.getProxyClass}:
1.300 + *
1.301 + * <ul>
1.302 + * <li>All of the {@code Class} objects in the
1.303 + * {@code interfaces} array must represent interfaces, not
1.304 + * classes or primitive types.
1.305 + *
1.306 + * <li>No two elements in the {@code interfaces} array may
1.307 + * refer to identical {@code Class} objects.
1.308 + *
1.309 + * <li>All of the interface types must be visible by name through the
1.310 + * specified class loader. In other words, for class loader
1.311 + * {@code cl} and every interface {@code i}, the following
1.312 + * expression must be true:
1.313 + * <pre>
1.314 + * Class.forName(i.getName(), false, cl) == i
1.315 + * </pre>
1.316 + *
1.317 + * <li>All non-public interfaces must be in the same package;
1.318 + * otherwise, it would not be possible for the proxy class to
1.319 + * implement all of the interfaces, regardless of what package it is
1.320 + * defined in.
1.321 + *
1.322 + * <li>For any set of member methods of the specified interfaces
1.323 + * that have the same signature:
1.324 + * <ul>
1.325 + * <li>If the return type of any of the methods is a primitive
1.326 + * type or void, then all of the methods must have that same
1.327 + * return type.
1.328 + * <li>Otherwise, one of the methods must have a return type that
1.329 + * is assignable to all of the return types of the rest of the
1.330 + * methods.
1.331 + * </ul>
1.332 + *
1.333 + * <li>The resulting proxy class must not exceed any limits imposed
1.334 + * on classes by the virtual machine. For example, the VM may limit
1.335 + * the number of interfaces that a class may implement to 65535; in
1.336 + * that case, the size of the {@code interfaces} array must not
1.337 + * exceed 65535.
1.338 + * </ul>
1.339 + *
1.340 + * <p>If any of these restrictions are violated,
1.341 + * {@code Proxy.getProxyClass} will throw an
1.342 + * {@code IllegalArgumentException}. If the {@code interfaces}
1.343 + * array argument or any of its elements are {@code null}, a
1.344 + * {@code NullPointerException} will be thrown.
1.345 + *
1.346 + * <p>Note that the order of the specified proxy interfaces is
1.347 + * significant: two requests for a proxy class with the same combination
1.348 + * of interfaces but in a different order will result in two distinct
1.349 + * proxy classes.
1.350 + *
1.351 + * @param loader the class loader to define the proxy class
1.352 + * @param interfaces the list of interfaces for the proxy class
1.353 + * to implement
1.354 + * @return a proxy class that is defined in the specified class loader
1.355 + * and that implements the specified interfaces
1.356 + * @throws IllegalArgumentException if any of the restrictions on the
1.357 + * parameters that may be passed to {@code getProxyClass}
1.358 + * are violated
1.359 + * @throws NullPointerException if the {@code interfaces} array
1.360 + * argument or any of its elements are {@code null}
1.361 + */
1.362 + public static Class<?> getProxyClass(ClassLoader loader,
1.363 + Class<?>... interfaces)
1.364 + throws IllegalArgumentException
1.365 + {
1.366 + if (interfaces.length > 65535) {
1.367 + throw new IllegalArgumentException("interface limit exceeded");
1.368 + }
1.369 +
1.370 + Class<?> proxyClass = null;
1.371 +
1.372 + /* collect interface names to use as key for proxy class cache */
1.373 + String[] interfaceNames = new String[interfaces.length];
1.374 +
1.375 + // for detecting duplicates
1.376 + Set<Class<?>> interfaceSet = new HashSet<>();
1.377 +
1.378 + for (int i = 0; i < interfaces.length; i++) {
1.379 + /*
1.380 + * Verify that the class loader resolves the name of this
1.381 + * interface to the same Class object.
1.382 + */
1.383 + String interfaceName = interfaces[i].getName();
1.384 + Class<?> interfaceClass = null;
1.385 + try {
1.386 + interfaceClass = Class.forName(interfaceName, false, loader);
1.387 + } catch (ClassNotFoundException e) {
1.388 + }
1.389 + if (interfaceClass != interfaces[i]) {
1.390 + throw new IllegalArgumentException(
1.391 + interfaces[i] + " is not visible from class loader");
1.392 + }
1.393 +
1.394 + /*
1.395 + * Verify that the Class object actually represents an
1.396 + * interface.
1.397 + */
1.398 + if (!interfaceClass.isInterface()) {
1.399 + throw new IllegalArgumentException(
1.400 + interfaceClass.getName() + " is not an interface");
1.401 + }
1.402 +
1.403 + /*
1.404 + * Verify that this interface is not a duplicate.
1.405 + */
1.406 + if (interfaceSet.contains(interfaceClass)) {
1.407 + throw new IllegalArgumentException(
1.408 + "repeated interface: " + interfaceClass.getName());
1.409 + }
1.410 + interfaceSet.add(interfaceClass);
1.411 +
1.412 + interfaceNames[i] = interfaceName;
1.413 + }
1.414 +
1.415 + /*
1.416 + * Using string representations of the proxy interfaces as
1.417 + * keys in the proxy class cache (instead of their Class
1.418 + * objects) is sufficient because we require the proxy
1.419 + * interfaces to be resolvable by name through the supplied
1.420 + * class loader, and it has the advantage that using a string
1.421 + * representation of a class makes for an implicit weak
1.422 + * reference to the class.
1.423 + */
1.424 + List<String> key = Arrays.asList(interfaceNames);
1.425 +
1.426 + /*
1.427 + * Find or create the proxy class cache for the class loader.
1.428 + */
1.429 + Map<List<String>, Object> cache;
1.430 + synchronized (loaderToCache) {
1.431 + cache = loaderToCache.get(loader);
1.432 + if (cache == null) {
1.433 + cache = new HashMap<>();
1.434 + loaderToCache.put(loader, cache);
1.435 + }
1.436 + /*
1.437 + * This mapping will remain valid for the duration of this
1.438 + * method, without further synchronization, because the mapping
1.439 + * will only be removed if the class loader becomes unreachable.
1.440 + */
1.441 + }
1.442 +
1.443 + /*
1.444 + * Look up the list of interfaces in the proxy class cache using
1.445 + * the key. This lookup will result in one of three possible
1.446 + * kinds of values:
1.447 + * null, if there is currently no proxy class for the list of
1.448 + * interfaces in the class loader,
1.449 + * the pendingGenerationMarker object, if a proxy class for the
1.450 + * list of interfaces is currently being generated,
1.451 + * or a weak reference to a Class object, if a proxy class for
1.452 + * the list of interfaces has already been generated.
1.453 + */
1.454 + synchronized (cache) {
1.455 + /*
1.456 + * Note that we need not worry about reaping the cache for
1.457 + * entries with cleared weak references because if a proxy class
1.458 + * has been garbage collected, its class loader will have been
1.459 + * garbage collected as well, so the entire cache will be reaped
1.460 + * from the loaderToCache map.
1.461 + */
1.462 + do {
1.463 + Object value = cache.get(key);
1.464 + if (value instanceof Reference) {
1.465 + proxyClass = (Class<?>) ((Reference) value).get();
1.466 + }
1.467 + if (proxyClass != null) {
1.468 + // proxy class already generated: return it
1.469 + return proxyClass;
1.470 + } else if (value == pendingGenerationMarker) {
1.471 + // proxy class being generated: wait for it
1.472 + try {
1.473 + cache.wait();
1.474 + } catch (InterruptedException e) {
1.475 + /*
1.476 + * The class generation that we are waiting for should
1.477 + * take a small, bounded time, so we can safely ignore
1.478 + * thread interrupts here.
1.479 + */
1.480 + }
1.481 + continue;
1.482 + } else {
1.483 + /*
1.484 + * No proxy class for this list of interfaces has been
1.485 + * generated or is being generated, so we will go and
1.486 + * generate it now. Mark it as pending generation.
1.487 + */
1.488 + cache.put(key, pendingGenerationMarker);
1.489 + break;
1.490 + }
1.491 + } while (true);
1.492 + }
1.493 +
1.494 + try {
1.495 + String proxyPkg = null; // package to define proxy class in
1.496 +
1.497 + /*
1.498 + * Record the package of a non-public proxy interface so that the
1.499 + * proxy class will be defined in the same package. Verify that
1.500 + * all non-public proxy interfaces are in the same package.
1.501 + */
1.502 + for (int i = 0; i < interfaces.length; i++) {
1.503 + int flags = interfaces[i].getModifiers();
1.504 + if (!Modifier.isPublic(flags)) {
1.505 + String name = interfaces[i].getName();
1.506 + int n = name.lastIndexOf('.');
1.507 + String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
1.508 + if (proxyPkg == null) {
1.509 + proxyPkg = pkg;
1.510 + } else if (!pkg.equals(proxyPkg)) {
1.511 + throw new IllegalArgumentException(
1.512 + "non-public interfaces from different packages");
1.513 + }
1.514 + }
1.515 + }
1.516 +
1.517 + if (proxyPkg == null) { // if no non-public proxy interfaces,
1.518 + proxyPkg = ""; // use the unnamed package
1.519 + }
1.520 +
1.521 + {
1.522 + /*
1.523 + * Choose a name for the proxy class to generate.
1.524 + */
1.525 + long num;
1.526 + synchronized (nextUniqueNumberLock) {
1.527 + num = nextUniqueNumber++;
1.528 + }
1.529 + String proxyName = proxyPkg + proxyClassNamePrefix + num;
1.530 + /*
1.531 + * Verify that the class loader hasn't already
1.532 + * defined a class with the chosen name.
1.533 + */
1.534 +
1.535 + /*
1.536 + * Generate the specified proxy class.
1.537 + */
1.538 + Generator gen = new Generator(proxyName, interfaces);
1.539 + final byte[] proxyClassFile = gen.generateClassFile();
1.540 + try {
1.541 + proxyClass = defineClass0(loader, proxyName,
1.542 + proxyClassFile);
1.543 + } catch (ClassFormatError e) {
1.544 + /*
1.545 + * A ClassFormatError here means that (barring bugs in the
1.546 + * proxy class generation code) there was some other
1.547 + * invalid aspect of the arguments supplied to the proxy
1.548 + * class creation (such as virtual machine limitations
1.549 + * exceeded).
1.550 + */
1.551 + throw new IllegalArgumentException(e.toString());
1.552 + }
1.553 + gen.fillInMethods(proxyClass);
1.554 + }
1.555 + // add to set of all generated proxy classes, for isProxyClass
1.556 + proxyClasses.put(proxyClass, null);
1.557 +
1.558 + } finally {
1.559 + /*
1.560 + * We must clean up the "pending generation" state of the proxy
1.561 + * class cache entry somehow. If a proxy class was successfully
1.562 + * generated, store it in the cache (with a weak reference);
1.563 + * otherwise, remove the reserved entry. In all cases, notify
1.564 + * all waiters on reserved entries in this cache.
1.565 + */
1.566 + synchronized (cache) {
1.567 + if (proxyClass != null) {
1.568 + cache.put(key, new WeakReference<Class<?>>(proxyClass));
1.569 + } else {
1.570 + cache.remove(key);
1.571 + }
1.572 + cache.notifyAll();
1.573 + }
1.574 + }
1.575 + return proxyClass;
1.576 + }
1.577 +
1.578 + /**
1.579 + * Returns an instance of a proxy class for the specified interfaces
1.580 + * that dispatches method invocations to the specified invocation
1.581 + * handler. This method is equivalent to:
1.582 + * <pre>
1.583 + * Proxy.getProxyClass(loader, interfaces).
1.584 + * getConstructor(new Class[] { InvocationHandler.class }).
1.585 + * newInstance(new Object[] { handler });
1.586 + * </pre>
1.587 + *
1.588 + * <p>{@code Proxy.newProxyInstance} throws
1.589 + * {@code IllegalArgumentException} for the same reasons that
1.590 + * {@code Proxy.getProxyClass} does.
1.591 + *
1.592 + * @param loader the class loader to define the proxy class
1.593 + * @param interfaces the list of interfaces for the proxy class
1.594 + * to implement
1.595 + * @param h the invocation handler to dispatch method invocations to
1.596 + * @return a proxy instance with the specified invocation handler of a
1.597 + * proxy class that is defined by the specified class loader
1.598 + * and that implements the specified interfaces
1.599 + * @throws IllegalArgumentException if any of the restrictions on the
1.600 + * parameters that may be passed to {@code getProxyClass}
1.601 + * are violated
1.602 + * @throws NullPointerException if the {@code interfaces} array
1.603 + * argument or any of its elements are {@code null}, or
1.604 + * if the invocation handler, {@code h}, is
1.605 + * {@code null}
1.606 + */
1.607 + public static Object newProxyInstance(ClassLoader loader,
1.608 + Class<?>[] interfaces,
1.609 + InvocationHandler h)
1.610 + throws IllegalArgumentException
1.611 + {
1.612 + if (h == null) {
1.613 + throw new NullPointerException();
1.614 + }
1.615 +
1.616 + /*
1.617 + * Look up or generate the designated proxy class.
1.618 + */
1.619 + Class<?> cl = getProxyClass(loader, interfaces);
1.620 +
1.621 + /*
1.622 + * Invoke its constructor with the designated invocation handler.
1.623 + */
1.624 + try {
1.625 + Constructor cons = cl.getConstructor(constructorParams);
1.626 + return cons.newInstance(new Object[] { h });
1.627 + } catch (NoSuchMethodException e) {
1.628 + throw new InternalError(e.toString());
1.629 + } catch (IllegalAccessException e) {
1.630 + throw new InternalError(e.toString());
1.631 + } catch (InstantiationException e) {
1.632 + throw new InternalError(e.toString());
1.633 + } catch (InvocationTargetException e) {
1.634 + throw new InternalError(e.toString());
1.635 + }
1.636 + }
1.637 +
1.638 + /**
1.639 + * Returns true if and only if the specified class was dynamically
1.640 + * generated to be a proxy class using the {@code getProxyClass}
1.641 + * method or the {@code newProxyInstance} method.
1.642 + *
1.643 + * <p>The reliability of this method is important for the ability
1.644 + * to use it to make security decisions, so its implementation should
1.645 + * not just test if the class in question extends {@code Proxy}.
1.646 + *
1.647 + * @param cl the class to test
1.648 + * @return {@code true} if the class is a proxy class and
1.649 + * {@code false} otherwise
1.650 + * @throws NullPointerException if {@code cl} is {@code null}
1.651 + */
1.652 + public static boolean isProxyClass(Class<?> cl) {
1.653 + if (cl == null) {
1.654 + throw new NullPointerException();
1.655 + }
1.656 +
1.657 + return proxyClasses.containsKey(cl);
1.658 + }
1.659 +
1.660 + /**
1.661 + * Returns the invocation handler for the specified proxy instance.
1.662 + *
1.663 + * @param proxy the proxy instance to return the invocation handler for
1.664 + * @return the invocation handler for the proxy instance
1.665 + * @throws IllegalArgumentException if the argument is not a
1.666 + * proxy instance
1.667 + */
1.668 + public static InvocationHandler getInvocationHandler(Object proxy)
1.669 + throws IllegalArgumentException
1.670 + {
1.671 + /*
1.672 + * Verify that the object is actually a proxy instance.
1.673 + */
1.674 + if (!isProxyClass(proxy.getClass())) {
1.675 + throw new IllegalArgumentException("not a proxy instance");
1.676 + }
1.677 +
1.678 + ProxyImpl p = (ProxyImpl) proxy;
1.679 + return p.h;
1.680 + }
1.681 +
1.682 + @JavaScriptBody(args = { "ignore", "name", "byteCode" },
1.683 + body = "return vm._reload(name, byteCode).constructor.$class;"
1.684 + )
1.685 + private static native Class defineClass0(
1.686 + ClassLoader loader, String name, byte[] b
1.687 + );
1.688 +
1.689 + private static class Generator {
1.690 + /*
1.691 + * In the comments below, "JVMS" refers to The Java Virtual Machine
1.692 + * Specification Second Edition and "JLS" refers to the original
1.693 + * version of The Java Language Specification, unless otherwise
1.694 + * specified.
1.695 + */
1.696 +
1.697 + /* need 1.6 bytecode */
1.698 + private static final int CLASSFILE_MAJOR_VERSION = 50;
1.699 + private static final int CLASSFILE_MINOR_VERSION = 0;
1.700 +
1.701 + /*
1.702 + * beginning of constants copied from
1.703 + * sun.tools.java.RuntimeConstants (which no longer exists):
1.704 + */
1.705 +
1.706 + /* constant pool tags */
1.707 + private static final int CONSTANT_UTF8 = 1;
1.708 + private static final int CONSTANT_UNICODE = 2;
1.709 + private static final int CONSTANT_INTEGER = 3;
1.710 + private static final int CONSTANT_FLOAT = 4;
1.711 + private static final int CONSTANT_LONG = 5;
1.712 + private static final int CONSTANT_DOUBLE = 6;
1.713 + private static final int CONSTANT_CLASS = 7;
1.714 + private static final int CONSTANT_STRING = 8;
1.715 + private static final int CONSTANT_FIELD = 9;
1.716 + private static final int CONSTANT_METHOD = 10;
1.717 + private static final int CONSTANT_INTERFACEMETHOD = 11;
1.718 + private static final int CONSTANT_NAMEANDTYPE = 12;
1.719 +
1.720 + /* access and modifier flags */
1.721 + private static final int ACC_PUBLIC = 0x00000001;
1.722 + private static final int ACC_FINAL = 0x00000010;
1.723 + private static final int ACC_SUPER = 0x00000020;
1.724 +
1.725 + // end of constants copied from sun.tools.java.RuntimeConstants
1.726 + /**
1.727 + * name of the superclass of proxy classes
1.728 + */
1.729 + private final static String superclassName = "java/lang/reflect/Proxy";
1.730 +
1.731 + /**
1.732 + * name of field for storing a proxy instance's invocation handler
1.733 + */
1.734 + private final static String handlerFieldName = "h";
1.735 +
1.736 + /* preloaded Method objects for methods in java.lang.Object */
1.737 + private static Method hashCodeMethod;
1.738 + private static Method equalsMethod;
1.739 + private static Method toStringMethod;
1.740 +
1.741 + static {
1.742 + try {
1.743 + hashCodeMethod = Object.class.getMethod("hashCode");
1.744 + equalsMethod
1.745 + = Object.class.getMethod("equals", new Class[]{Object.class});
1.746 + toStringMethod = Object.class.getMethod("toString");
1.747 + } catch (NoSuchMethodException e) {
1.748 + throw new IllegalStateException(e.getMessage());
1.749 + }
1.750 + }
1.751 +
1.752 + /**
1.753 + * name of proxy class
1.754 + */
1.755 + private String className;
1.756 +
1.757 + /**
1.758 + * proxy interfaces
1.759 + */
1.760 + private Class[] interfaces;
1.761 +
1.762 + /**
1.763 + * constant pool of class being generated
1.764 + */
1.765 + private ConstantPool cp = new ConstantPool();
1.766 +
1.767 + /**
1.768 + * maps method signature string to list of ProxyMethod objects for proxy
1.769 + * methods with that signature
1.770 + */
1.771 + private Map<String, List<ProxyMethod>> proxyMethods
1.772 + = new HashMap<String, List<ProxyMethod>>();
1.773 +
1.774 + /**
1.775 + * count of ProxyMethod objects added to proxyMethods
1.776 + */
1.777 + private int proxyMethodCount = 0;
1.778 +
1.779 + /**
1.780 + * Construct a ProxyGenerator to generate a proxy class with the
1.781 + * specified name and for the given interfaces.
1.782 + *
1.783 + * A ProxyGenerator object contains the state for the ongoing generation
1.784 + * of a particular proxy class.
1.785 + */
1.786 + private Generator(String className, Class[] interfaces) {
1.787 + this.className = className;
1.788 + this.interfaces = interfaces;
1.789 + }
1.790 +
1.791 + /**
1.792 + * Generate a class file for the proxy class. This method drives the
1.793 + * class file generation process.
1.794 + */
1.795 + private byte[] generateClassFile() {
1.796 +
1.797 + /* ============================================================
1.798 + * Step 1: Assemble ProxyMethod objects for all methods to
1.799 + * generate proxy dispatching code for.
1.800 + */
1.801 +
1.802 + /*
1.803 + * Record that proxy methods are needed for the hashCode, equals,
1.804 + * and toString methods of java.lang.Object. This is done before
1.805 + * the methods from the proxy interfaces so that the methods from
1.806 + * java.lang.Object take precedence over duplicate methods in the
1.807 + * proxy interfaces.
1.808 + */
1.809 + addProxyMethod(hashCodeMethod, Object.class);
1.810 + addProxyMethod(equalsMethod, Object.class);
1.811 + addProxyMethod(toStringMethod, Object.class);
1.812 +
1.813 + /*
1.814 + * Now record all of the methods from the proxy interfaces, giving
1.815 + * earlier interfaces precedence over later ones with duplicate
1.816 + * methods.
1.817 + */
1.818 + for (int i = 0; i < interfaces.length; i++) {
1.819 + Method[] methods = interfaces[i].getMethods();
1.820 + for (int j = 0; j < methods.length; j++) {
1.821 + addProxyMethod(methods[j], interfaces[i]);
1.822 + }
1.823 + }
1.824 +
1.825 + /*
1.826 + * For each set of proxy methods with the same signature,
1.827 + * verify that the methods' return types are compatible.
1.828 + */
1.829 + for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
1.830 + checkReturnTypes(sigmethods);
1.831 + }
1.832 +
1.833 + /* ============================================================
1.834 + * Step 2: Assemble FieldInfo and MethodInfo structs for all of
1.835 + * fields and methods in the class we are generating.
1.836 + */
1.837 +
1.838 + // will be done in fillInMethods
1.839 +
1.840 + /* ============================================================
1.841 + * Step 3: Write the final class file.
1.842 + */
1.843 +
1.844 + /*
1.845 + * Make sure that constant pool indexes are reserved for the
1.846 + * following items before starting to write the final class file.
1.847 + */
1.848 + cp.getClass(dotToSlash(className));
1.849 + cp.getClass(superclassName);
1.850 + for (int i = 0; i < interfaces.length; i++) {
1.851 + cp.getClass(dotToSlash(interfaces[i].getName()));
1.852 + }
1.853 +
1.854 + /*
1.855 + * Disallow new constant pool additions beyond this point, since
1.856 + * we are about to write the final constant pool table.
1.857 + */
1.858 + cp.setReadOnly();
1.859 +
1.860 + ByteArrayOutputStream bout = new ByteArrayOutputStream();
1.861 + DataOutputStream dout = new DataOutputStream(bout);
1.862 +
1.863 + try {
1.864 + /*
1.865 + * Write all the items of the "ClassFile" structure.
1.866 + * See JVMS section 4.1.
1.867 + */
1.868 + // u4 magic;
1.869 + dout.writeInt(0xCAFEBABE);
1.870 + // u2 minor_version;
1.871 + dout.writeShort(CLASSFILE_MINOR_VERSION);
1.872 + // u2 major_version;
1.873 + dout.writeShort(CLASSFILE_MAJOR_VERSION);
1.874 +
1.875 + cp.write(dout); // (write constant pool)
1.876 +
1.877 + // u2 access_flags;
1.878 + dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
1.879 + // u2 this_class;
1.880 + dout.writeShort(cp.getClass(dotToSlash(className)));
1.881 + // u2 super_class;
1.882 + dout.writeShort(cp.getClass(superclassName));
1.883 +
1.884 + // u2 interfaces_count;
1.885 + dout.writeShort(interfaces.length);
1.886 + // u2 interfaces[interfaces_count];
1.887 + for (int i = 0; i < interfaces.length; i++) {
1.888 + dout.writeShort(cp.getClass(
1.889 + dotToSlash(interfaces[i].getName())));
1.890 + }
1.891 +
1.892 + // u2 fields_count;
1.893 + dout.writeShort(0);
1.894 +
1.895 + // u2 methods_count;
1.896 + dout.writeShort(0);
1.897 +
1.898 + // u2 attributes_count;
1.899 + dout.writeShort(0); // (no ClassFile attributes for proxy classes)
1.900 +
1.901 + } catch (IOException e) {
1.902 + throw new InternalError("unexpected I/O Exception");
1.903 + }
1.904 +
1.905 + return bout.toByteArray();
1.906 + }
1.907 +
1.908 + @JavaScriptBody(args = { "c", "sig", "method", "primitive" }, body =
1.909 + "var p = c.cnstr.prototype;\n" +
1.910 + "p[sig] = function() {\n" +
1.911 + " var h = this._h();\n" +
1.912 + " var res = h.invoke__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_reflect_Method_2_3Ljava_lang_Object_2(this, method, arguments);\n" +
1.913 + " \n" +
1.914 + " \n" +
1.915 + " return res;\n" +
1.916 + "};"
1.917 + )
1.918 + private static native void defineMethod(Class<?> proxyClass, String sig, Method method, boolean primitive);
1.919 +
1.920 + @JavaScriptBody(args = "c", body =
1.921 + "var h = c.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2 = function(h) {\n"
1.922 + + " c.superclass.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2.call(this, h);\n"
1.923 + + "}\n"
1.924 + + "h.cls = c.cnstr;\n"
1.925 + )
1.926 + private static native void defineConstructor(Class<?> proxyClass);
1.927 +
1.928 + final void fillInMethods(Class<?> proxyClass) {
1.929 + for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
1.930 + for (ProxyMethod pm : sigmethods) {
1.931 + String sig = MethodImpl.toSignature(pm.method);
1.932 + defineMethod(proxyClass, sig, pm.method, pm.method.getReturnType().isPrimitive());
1.933 + }
1.934 + }
1.935 + defineConstructor(proxyClass);
1.936 + }
1.937 +
1.938 + /**
1.939 + * Add another method to be proxied, either by creating a new
1.940 + * ProxyMethod object or augmenting an old one for a duplicate method.
1.941 + *
1.942 + * "fromClass" indicates the proxy interface that the method was found
1.943 + * through, which may be different from (a subinterface of) the method's
1.944 + * "declaring class". Note that the first Method object passed for a
1.945 + * given name and descriptor identifies the Method object (and thus the
1.946 + * declaring class) that will be passed to the invocation handler's
1.947 + * "invoke" method for a given set of duplicate methods.
1.948 + */
1.949 + private void addProxyMethod(Method m, Class fromClass) {
1.950 + String name = m.getName();
1.951 + Class[] parameterTypes = m.getParameterTypes();
1.952 + Class returnType = m.getReturnType();
1.953 + Class[] exceptionTypes = m.getExceptionTypes();
1.954 +
1.955 + String sig = MethodImpl.toSignature(m);
1.956 + List<ProxyMethod> sigmethods = proxyMethods.get(sig);
1.957 + if (sigmethods != null) {
1.958 + for (ProxyMethod pm : sigmethods) {
1.959 + if (returnType == pm.returnType) {
1.960 + /*
1.961 + * Found a match: reduce exception types to the
1.962 + * greatest set of exceptions that can thrown
1.963 + * compatibly with the throws clauses of both
1.964 + * overridden methods.
1.965 + */
1.966 + List<Class<?>> legalExceptions = new ArrayList<Class<?>>();
1.967 + collectCompatibleTypes(
1.968 + exceptionTypes, pm.exceptionTypes, legalExceptions);
1.969 + collectCompatibleTypes(
1.970 + pm.exceptionTypes, exceptionTypes, legalExceptions);
1.971 + pm.exceptionTypes = new Class[legalExceptions.size()];
1.972 + pm.exceptionTypes
1.973 + = legalExceptions.toArray(pm.exceptionTypes);
1.974 + return;
1.975 + }
1.976 + }
1.977 + } else {
1.978 + sigmethods = new ArrayList<ProxyMethod>(3);
1.979 + proxyMethods.put(sig, sigmethods);
1.980 + }
1.981 + sigmethods.add(new ProxyMethod(m, name, parameterTypes, returnType,
1.982 + exceptionTypes, fromClass));
1.983 + }
1.984 +
1.985 + /**
1.986 + * For a given set of proxy methods with the same signature, check that
1.987 + * their return types are compatible according to the Proxy
1.988 + * specification.
1.989 + *
1.990 + * Specifically, if there is more than one such method, then all of the
1.991 + * return types must be reference types, and there must be one return
1.992 + * type that is assignable to each of the rest of them.
1.993 + */
1.994 + private static void checkReturnTypes(List<ProxyMethod> methods) {
1.995 + /*
1.996 + * If there is only one method with a given signature, there
1.997 + * cannot be a conflict. This is the only case in which a
1.998 + * primitive (or void) return type is allowed.
1.999 + */
1.1000 + if (methods.size() < 2) {
1.1001 + return;
1.1002 + }
1.1003 +
1.1004 + /*
1.1005 + * List of return types that are not yet known to be
1.1006 + * assignable from ("covered" by) any of the others.
1.1007 + */
1.1008 + LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>();
1.1009 +
1.1010 + nextNewReturnType:
1.1011 + for (ProxyMethod pm : methods) {
1.1012 + Class<?> newReturnType = pm.returnType;
1.1013 + if (newReturnType.isPrimitive()) {
1.1014 + throw new IllegalArgumentException(
1.1015 + "methods with same signature "
1.1016 + + getFriendlyMethodSignature(pm.methodName,
1.1017 + pm.parameterTypes)
1.1018 + + " but incompatible return types: "
1.1019 + + newReturnType.getName() + " and others");
1.1020 + }
1.1021 + boolean added = false;
1.1022 +
1.1023 + /*
1.1024 + * Compare the new return type to the existing uncovered
1.1025 + * return types.
1.1026 + */
1.1027 + ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
1.1028 + while (liter.hasNext()) {
1.1029 + Class<?> uncoveredReturnType = liter.next();
1.1030 +
1.1031 + /*
1.1032 + * If an existing uncovered return type is assignable
1.1033 + * to this new one, then we can forget the new one.
1.1034 + */
1.1035 + if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
1.1036 + assert !added;
1.1037 + continue nextNewReturnType;
1.1038 + }
1.1039 +
1.1040 + /*
1.1041 + * If the new return type is assignable to an existing
1.1042 + * uncovered one, then should replace the existing one
1.1043 + * with the new one (or just forget the existing one,
1.1044 + * if the new one has already be put in the list).
1.1045 + */
1.1046 + if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
1.1047 + // (we can assume that each return type is unique)
1.1048 + if (!added) {
1.1049 + liter.set(newReturnType);
1.1050 + added = true;
1.1051 + } else {
1.1052 + liter.remove();
1.1053 + }
1.1054 + }
1.1055 + }
1.1056 +
1.1057 + /*
1.1058 + * If we got through the list of existing uncovered return
1.1059 + * types without an assignability relationship, then add
1.1060 + * the new return type to the list of uncovered ones.
1.1061 + */
1.1062 + if (!added) {
1.1063 + uncoveredReturnTypes.add(newReturnType);
1.1064 + }
1.1065 + }
1.1066 +
1.1067 + /*
1.1068 + * We shouldn't end up with more than one return type that is
1.1069 + * not assignable from any of the others.
1.1070 + */
1.1071 + if (uncoveredReturnTypes.size() > 1) {
1.1072 + ProxyMethod pm = methods.get(0);
1.1073 + throw new IllegalArgumentException(
1.1074 + "methods with same signature "
1.1075 + + getFriendlyMethodSignature(pm.methodName, pm.parameterTypes)
1.1076 + + " but incompatible return types: " + uncoveredReturnTypes);
1.1077 + }
1.1078 + }
1.1079 +
1.1080 +
1.1081 + /**
1.1082 + * A ProxyMethod object represents a proxy method in the proxy class
1.1083 + * being generated: a method whose implementation will encode and
1.1084 + * dispatch invocations to the proxy instance's invocation handler.
1.1085 + */
1.1086 + private class ProxyMethod {
1.1087 +
1.1088 + private final Method method;
1.1089 + public String methodName;
1.1090 + public Class[] parameterTypes;
1.1091 + public Class returnType;
1.1092 + public Class[] exceptionTypes;
1.1093 + public Class fromClass;
1.1094 + public String methodFieldName;
1.1095 +
1.1096 + private ProxyMethod(Method m,
1.1097 + String methodName, Class[] parameterTypes,
1.1098 + Class returnType, Class[] exceptionTypes,
1.1099 + Class fromClass
1.1100 + ) {
1.1101 + this.method = m;
1.1102 + this.methodName = methodName;
1.1103 + this.parameterTypes = parameterTypes;
1.1104 + this.returnType = returnType;
1.1105 + this.exceptionTypes = exceptionTypes;
1.1106 + this.fromClass = fromClass;
1.1107 + this.methodFieldName = "m" + proxyMethodCount++;
1.1108 + }
1.1109 +
1.1110 + }
1.1111 +
1.1112 + /*
1.1113 + * ==================== General Utility Methods ====================
1.1114 + */
1.1115 + /**
1.1116 + * Convert a fully qualified class name that uses '.' as the package
1.1117 + * separator, the external representation used by the Java language and
1.1118 + * APIs, to a fully qualified class name that uses '/' as the package
1.1119 + * separator, the representation used in the class file format (see JVMS
1.1120 + * section 4.2).
1.1121 + */
1.1122 + private static String dotToSlash(String name) {
1.1123 + return name.replace('.', '/');
1.1124 + }
1.1125 +
1.1126 + /**
1.1127 + * Return the list of "parameter descriptor" strings enclosed in
1.1128 + * parentheses corresponding to the given parameter types (in other
1.1129 + * words, a method descriptor without a return descriptor). This string
1.1130 + * is useful for constructing string keys for methods without regard to
1.1131 + * their return type.
1.1132 + */
1.1133 + private static String getParameterDescriptors(Class[] parameterTypes) {
1.1134 + StringBuilder desc = new StringBuilder("(");
1.1135 + for (int i = 0; i < parameterTypes.length; i++) {
1.1136 + desc.append(getFieldType(parameterTypes[i]));
1.1137 + }
1.1138 + desc.append(')');
1.1139 + return desc.toString();
1.1140 + }
1.1141 +
1.1142 + /**
1.1143 + * Return the "field type" string for the given type, appropriate for a
1.1144 + * field descriptor, a parameter descriptor, or a return descriptor
1.1145 + * other than "void". See JVMS section 4.3.2.
1.1146 + */
1.1147 + private static String getFieldType(Class type) {
1.1148 + if (type.isPrimitive()) {
1.1149 + return PrimitiveTypeInfo.get(type).baseTypeString;
1.1150 + } else if (type.isArray()) {
1.1151 + /*
1.1152 + * According to JLS 20.3.2, the getName() method on Class does
1.1153 + * return the VM type descriptor format for array classes (only);
1.1154 + * using that should be quicker than the otherwise obvious code:
1.1155 + *
1.1156 + * return "[" + getTypeDescriptor(type.getComponentType());
1.1157 + */
1.1158 + return type.getName().replace('.', '/');
1.1159 + } else {
1.1160 + return "L" + dotToSlash(type.getName()) + ";";
1.1161 + }
1.1162 + }
1.1163 +
1.1164 + /**
1.1165 + * Returns a human-readable string representing the signature of a
1.1166 + * method with the given name and parameter types.
1.1167 + */
1.1168 + private static String getFriendlyMethodSignature(String name,
1.1169 + Class[] parameterTypes) {
1.1170 + StringBuilder sig = new StringBuilder(name);
1.1171 + sig.append('(');
1.1172 + for (int i = 0; i < parameterTypes.length; i++) {
1.1173 + if (i > 0) {
1.1174 + sig.append(',');
1.1175 + }
1.1176 + Class parameterType = parameterTypes[i];
1.1177 + int dimensions = 0;
1.1178 + while (parameterType.isArray()) {
1.1179 + parameterType = parameterType.getComponentType();
1.1180 + dimensions++;
1.1181 + }
1.1182 + sig.append(parameterType.getName());
1.1183 + while (dimensions-- > 0) {
1.1184 + sig.append("[]");
1.1185 + }
1.1186 + }
1.1187 + sig.append(')');
1.1188 + return sig.toString();
1.1189 + }
1.1190 +
1.1191 + /**
1.1192 + * Add to the given list all of the types in the "from" array that are
1.1193 + * not already contained in the list and are assignable to at least one
1.1194 + * of the types in the "with" array.
1.1195 + *
1.1196 + * This method is useful for computing the greatest common set of
1.1197 + * declared exceptions from duplicate methods inherited from different
1.1198 + * interfaces.
1.1199 + */
1.1200 + private static void collectCompatibleTypes(Class<?>[] from,
1.1201 + Class<?>[] with,
1.1202 + List<Class<?>> list) {
1.1203 + for (int i = 0; i < from.length; i++) {
1.1204 + if (!list.contains(from[i])) {
1.1205 + for (int j = 0; j < with.length; j++) {
1.1206 + if (with[j].isAssignableFrom(from[i])) {
1.1207 + list.add(from[i]);
1.1208 + break;
1.1209 + }
1.1210 + }
1.1211 + }
1.1212 + }
1.1213 + }
1.1214 +
1.1215 +
1.1216 + /**
1.1217 + * A PrimitiveTypeInfo object contains assorted information about a
1.1218 + * primitive type in its public fields. The struct for a particular
1.1219 + * primitive type can be obtained using the static "get" method.
1.1220 + */
1.1221 + private static class PrimitiveTypeInfo {
1.1222 +
1.1223 + /**
1.1224 + * "base type" used in various descriptors (see JVMS section 4.3.2)
1.1225 + */
1.1226 + public String baseTypeString;
1.1227 +
1.1228 + /**
1.1229 + * name of corresponding wrapper class
1.1230 + */
1.1231 + public String wrapperClassName;
1.1232 +
1.1233 + /**
1.1234 + * method descriptor for wrapper class "valueOf" factory method
1.1235 + */
1.1236 + public String wrapperValueOfDesc;
1.1237 +
1.1238 + /**
1.1239 + * name of wrapper class method for retrieving primitive value
1.1240 + */
1.1241 + public String unwrapMethodName;
1.1242 +
1.1243 + /**
1.1244 + * descriptor of same method
1.1245 + */
1.1246 + public String unwrapMethodDesc;
1.1247 +
1.1248 + private static Map<Class, PrimitiveTypeInfo> table
1.1249 + = new HashMap<Class, PrimitiveTypeInfo>();
1.1250 +
1.1251 + static {
1.1252 + add(byte.class, Byte.class);
1.1253 + add(char.class, Character.class);
1.1254 + add(double.class, Double.class);
1.1255 + add(float.class, Float.class);
1.1256 + add(int.class, Integer.class);
1.1257 + add(long.class, Long.class);
1.1258 + add(short.class, Short.class);
1.1259 + add(boolean.class, Boolean.class);
1.1260 + }
1.1261 +
1.1262 + private static void add(Class primitiveClass, Class wrapperClass) {
1.1263 + table.put(primitiveClass,
1.1264 + new PrimitiveTypeInfo(primitiveClass, wrapperClass));
1.1265 + }
1.1266 +
1.1267 + private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) {
1.1268 + assert primitiveClass.isPrimitive();
1.1269 +
1.1270 + baseTypeString
1.1271 + = Array.newInstance(primitiveClass, 0)
1.1272 + .getClass().getName().substring(1);
1.1273 + wrapperClassName = dotToSlash(wrapperClass.getName());
1.1274 + wrapperValueOfDesc
1.1275 + = "(" + baseTypeString + ")L" + wrapperClassName + ";";
1.1276 + unwrapMethodName = primitiveClass.getName() + "Value";
1.1277 + unwrapMethodDesc = "()" + baseTypeString;
1.1278 + }
1.1279 +
1.1280 + public static PrimitiveTypeInfo get(Class cl) {
1.1281 + return table.get(cl);
1.1282 + }
1.1283 + }
1.1284 +
1.1285 + /**
1.1286 + * A ConstantPool object represents the constant pool of a class file
1.1287 + * being generated. This representation of a constant pool is designed
1.1288 + * specifically for use by ProxyGenerator; in particular, it assumes
1.1289 + * that constant pool entries will not need to be resorted (for example,
1.1290 + * by their type, as the Java compiler does), so that the final index
1.1291 + * value can be assigned and used when an entry is first created.
1.1292 + *
1.1293 + * Note that new entries cannot be created after the constant pool has
1.1294 + * been written to a class file. To prevent such logic errors, a
1.1295 + * ConstantPool instance can be marked "read only", so that further
1.1296 + * attempts to add new entries will fail with a runtime exception.
1.1297 + *
1.1298 + * See JVMS section 4.4 for more information about the constant pool of
1.1299 + * a class file.
1.1300 + */
1.1301 + private static class ConstantPool {
1.1302 +
1.1303 + /**
1.1304 + * list of constant pool entries, in constant pool index order.
1.1305 + *
1.1306 + * This list is used when writing the constant pool to a stream and
1.1307 + * for assigning the next index value. Note that element 0 of this
1.1308 + * list corresponds to constant pool index 1.
1.1309 + */
1.1310 + private List<Entry> pool = new ArrayList<Entry>(32);
1.1311 +
1.1312 + /**
1.1313 + * maps constant pool data of all types to constant pool indexes.
1.1314 + *
1.1315 + * This map is used to look up the index of an existing entry for
1.1316 + * values of all types.
1.1317 + */
1.1318 + private Map<Object, Short> map = new HashMap<Object, Short>(16);
1.1319 +
1.1320 + /**
1.1321 + * true if no new constant pool entries may be added
1.1322 + */
1.1323 + private boolean readOnly = false;
1.1324 +
1.1325 + /**
1.1326 + * Get or assign the index for a CONSTANT_Utf8 entry.
1.1327 + */
1.1328 + public short getUtf8(String s) {
1.1329 + if (s == null) {
1.1330 + throw new NullPointerException();
1.1331 + }
1.1332 + return getValue(s);
1.1333 + }
1.1334 +
1.1335 + /**
1.1336 + * Get or assign the index for a CONSTANT_Integer entry.
1.1337 + */
1.1338 + public short getInteger(int i) {
1.1339 + return getValue(new Integer(i));
1.1340 + }
1.1341 +
1.1342 + /**
1.1343 + * Get or assign the index for a CONSTANT_Float entry.
1.1344 + */
1.1345 + public short getFloat(float f) {
1.1346 + return getValue(new Float(f));
1.1347 + }
1.1348 +
1.1349 + /**
1.1350 + * Get or assign the index for a CONSTANT_Class entry.
1.1351 + */
1.1352 + public short getClass(String name) {
1.1353 + short utf8Index = getUtf8(name);
1.1354 + return getIndirect(new IndirectEntry(
1.1355 + CONSTANT_CLASS, utf8Index));
1.1356 + }
1.1357 +
1.1358 + /**
1.1359 + * Get or assign the index for a CONSTANT_String entry.
1.1360 + */
1.1361 + public short getString(String s) {
1.1362 + short utf8Index = getUtf8(s);
1.1363 + return getIndirect(new IndirectEntry(
1.1364 + CONSTANT_STRING, utf8Index));
1.1365 + }
1.1366 +
1.1367 + /**
1.1368 + * Get or assign the index for a CONSTANT_FieldRef entry.
1.1369 + */
1.1370 + public short getFieldRef(String className,
1.1371 + String name, String descriptor) {
1.1372 + short classIndex = getClass(className);
1.1373 + short nameAndTypeIndex = getNameAndType(name, descriptor);
1.1374 + return getIndirect(new IndirectEntry(
1.1375 + CONSTANT_FIELD, classIndex, nameAndTypeIndex));
1.1376 + }
1.1377 +
1.1378 + /**
1.1379 + * Get or assign the index for a CONSTANT_MethodRef entry.
1.1380 + */
1.1381 + public short getMethodRef(String className,
1.1382 + String name, String descriptor) {
1.1383 + short classIndex = getClass(className);
1.1384 + short nameAndTypeIndex = getNameAndType(name, descriptor);
1.1385 + return getIndirect(new IndirectEntry(
1.1386 + CONSTANT_METHOD, classIndex, nameAndTypeIndex));
1.1387 + }
1.1388 +
1.1389 + /**
1.1390 + * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
1.1391 + */
1.1392 + public short getInterfaceMethodRef(String className, String name,
1.1393 + String descriptor) {
1.1394 + short classIndex = getClass(className);
1.1395 + short nameAndTypeIndex = getNameAndType(name, descriptor);
1.1396 + return getIndirect(new IndirectEntry(
1.1397 + CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
1.1398 + }
1.1399 +
1.1400 + /**
1.1401 + * Get or assign the index for a CONSTANT_NameAndType entry.
1.1402 + */
1.1403 + public short getNameAndType(String name, String descriptor) {
1.1404 + short nameIndex = getUtf8(name);
1.1405 + short descriptorIndex = getUtf8(descriptor);
1.1406 + return getIndirect(new IndirectEntry(
1.1407 + CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
1.1408 + }
1.1409 +
1.1410 + /**
1.1411 + * Set this ConstantPool instance to be "read only".
1.1412 + *
1.1413 + * After this method has been called, further requests to get an
1.1414 + * index for a non-existent entry will cause an InternalError to be
1.1415 + * thrown instead of creating of the entry.
1.1416 + */
1.1417 + public void setReadOnly() {
1.1418 + readOnly = true;
1.1419 + }
1.1420 +
1.1421 + /**
1.1422 + * Write this constant pool to a stream as part of the class file
1.1423 + * format.
1.1424 + *
1.1425 + * This consists of writing the "constant_pool_count" and
1.1426 + * "constant_pool[]" items of the "ClassFile" structure, as
1.1427 + * described in JVMS section 4.1.
1.1428 + */
1.1429 + public void write(OutputStream out) throws IOException {
1.1430 + DataOutputStream dataOut = new DataOutputStream(out);
1.1431 +
1.1432 + // constant_pool_count: number of entries plus one
1.1433 + dataOut.writeShort(pool.size() + 1);
1.1434 +
1.1435 + for (Entry e : pool) {
1.1436 + e.write(dataOut);
1.1437 + }
1.1438 + }
1.1439 +
1.1440 + /**
1.1441 + * Add a new constant pool entry and return its index.
1.1442 + */
1.1443 + private short addEntry(Entry entry) {
1.1444 + pool.add(entry);
1.1445 + /*
1.1446 + * Note that this way of determining the index of the
1.1447 + * added entry is wrong if this pool supports
1.1448 + * CONSTANT_Long or CONSTANT_Double entries.
1.1449 + */
1.1450 + if (pool.size() >= 65535) {
1.1451 + throw new IllegalArgumentException(
1.1452 + "constant pool size limit exceeded");
1.1453 + }
1.1454 + return (short) pool.size();
1.1455 + }
1.1456 +
1.1457 + /**
1.1458 + * Get or assign the index for an entry of a type that contains a
1.1459 + * direct value. The type of the given object determines the type of
1.1460 + * the desired entry as follows:
1.1461 + *
1.1462 + * java.lang.String CONSTANT_Utf8 java.lang.Integer CONSTANT_Integer
1.1463 + * java.lang.Float CONSTANT_Float java.lang.Long CONSTANT_Long
1.1464 + * java.lang.Double CONSTANT_DOUBLE
1.1465 + */
1.1466 + private short getValue(Object key) {
1.1467 + Short index = map.get(key);
1.1468 + if (index != null) {
1.1469 + return index.shortValue();
1.1470 + } else {
1.1471 + if (readOnly) {
1.1472 + throw new InternalError(
1.1473 + "late constant pool addition: " + key);
1.1474 + }
1.1475 + short i = addEntry(new ValueEntry(key));
1.1476 + map.put(key, new Short(i));
1.1477 + return i;
1.1478 + }
1.1479 + }
1.1480 +
1.1481 + /**
1.1482 + * Get or assign the index for an entry of a type that contains
1.1483 + * references to other constant pool entries.
1.1484 + */
1.1485 + private short getIndirect(IndirectEntry e) {
1.1486 + Short index = map.get(e);
1.1487 + if (index != null) {
1.1488 + return index.shortValue();
1.1489 + } else {
1.1490 + if (readOnly) {
1.1491 + throw new InternalError("late constant pool addition");
1.1492 + }
1.1493 + short i = addEntry(e);
1.1494 + map.put(e, new Short(i));
1.1495 + return i;
1.1496 + }
1.1497 + }
1.1498 +
1.1499 + /**
1.1500 + * Entry is the abstact superclass of all constant pool entry types
1.1501 + * that can be stored in the "pool" list; its purpose is to define a
1.1502 + * common method for writing constant pool entries to a class file.
1.1503 + */
1.1504 + private static abstract class Entry {
1.1505 +
1.1506 + public abstract void write(DataOutputStream out)
1.1507 + throws IOException;
1.1508 + }
1.1509 +
1.1510 + /**
1.1511 + * ValueEntry represents a constant pool entry of a type that
1.1512 + * contains a direct value (see the comments for the "getValue"
1.1513 + * method for a list of such types).
1.1514 + *
1.1515 + * ValueEntry objects are not used as keys for their entries in the
1.1516 + * Map "map", so no useful hashCode or equals methods are defined.
1.1517 + */
1.1518 + private static class ValueEntry extends Entry {
1.1519 +
1.1520 + private Object value;
1.1521 +
1.1522 + public ValueEntry(Object value) {
1.1523 + this.value = value;
1.1524 + }
1.1525 +
1.1526 + public void write(DataOutputStream out) throws IOException {
1.1527 + if (value instanceof String) {
1.1528 + out.writeByte(CONSTANT_UTF8);
1.1529 + out.writeUTF((String) value);
1.1530 + } else if (value instanceof Integer) {
1.1531 + out.writeByte(CONSTANT_INTEGER);
1.1532 + out.writeInt(((Integer) value).intValue());
1.1533 + } else if (value instanceof Float) {
1.1534 + out.writeByte(CONSTANT_FLOAT);
1.1535 + out.writeFloat(((Float) value).floatValue());
1.1536 + } else if (value instanceof Long) {
1.1537 + out.writeByte(CONSTANT_LONG);
1.1538 + out.writeLong(((Long) value).longValue());
1.1539 + } else if (value instanceof Double) {
1.1540 + out.writeDouble(CONSTANT_DOUBLE);
1.1541 + out.writeDouble(((Double) value).doubleValue());
1.1542 + } else {
1.1543 + throw new InternalError("bogus value entry: " + value);
1.1544 + }
1.1545 + }
1.1546 + }
1.1547 +
1.1548 + /**
1.1549 + * IndirectEntry represents a constant pool entry of a type that
1.1550 + * references other constant pool entries, i.e., the following
1.1551 + * types:
1.1552 + *
1.1553 + * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
1.1554 + * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
1.1555 + * CONSTANT_NameAndType.
1.1556 + *
1.1557 + * Each of these entry types contains either one or two indexes of
1.1558 + * other constant pool entries.
1.1559 + *
1.1560 + * IndirectEntry objects are used as the keys for their entries in
1.1561 + * the Map "map", so the hashCode and equals methods are overridden
1.1562 + * to allow matching.
1.1563 + */
1.1564 + private static class IndirectEntry extends Entry {
1.1565 +
1.1566 + private int tag;
1.1567 + private short index0;
1.1568 + private short index1;
1.1569 +
1.1570 + /**
1.1571 + * Construct an IndirectEntry for a constant pool entry type
1.1572 + * that contains one index of another entry.
1.1573 + */
1.1574 + public IndirectEntry(int tag, short index) {
1.1575 + this.tag = tag;
1.1576 + this.index0 = index;
1.1577 + this.index1 = 0;
1.1578 + }
1.1579 +
1.1580 + /**
1.1581 + * Construct an IndirectEntry for a constant pool entry type
1.1582 + * that contains two indexes for other entries.
1.1583 + */
1.1584 + public IndirectEntry(int tag, short index0, short index1) {
1.1585 + this.tag = tag;
1.1586 + this.index0 = index0;
1.1587 + this.index1 = index1;
1.1588 + }
1.1589 +
1.1590 + public void write(DataOutputStream out) throws IOException {
1.1591 + out.writeByte(tag);
1.1592 + out.writeShort(index0);
1.1593 + /*
1.1594 + * If this entry type contains two indexes, write
1.1595 + * out the second, too.
1.1596 + */
1.1597 + if (tag == CONSTANT_FIELD
1.1598 + || tag == CONSTANT_METHOD
1.1599 + || tag == CONSTANT_INTERFACEMETHOD
1.1600 + || tag == CONSTANT_NAMEANDTYPE) {
1.1601 + out.writeShort(index1);
1.1602 + }
1.1603 + }
1.1604 +
1.1605 + public int hashCode() {
1.1606 + return tag + index0 + index1;
1.1607 + }
1.1608 +
1.1609 + public boolean equals(Object obj) {
1.1610 + if (obj instanceof IndirectEntry) {
1.1611 + IndirectEntry other = (IndirectEntry) obj;
1.1612 + if (tag == other.tag
1.1613 + && index0 == other.index0 && index1 == other.index1) {
1.1614 + return true;
1.1615 + }
1.1616 + }
1.1617 + return false;
1.1618 + }
1.1619 + }
1.1620 + }
1.1621 + }
1.1622 +
1.1623 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ProxyTest.java Mon Oct 21 14:34:12 2013 +0200
2.3 @@ -0,0 +1,71 @@
2.4 +/**
2.5 + * Back 2 Browser Bytecode Translator
2.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
2.7 + *
2.8 + * This program is free software: you can redistribute it and/or modify
2.9 + * it under the terms of the GNU General Public License as published by
2.10 + * the Free Software Foundation, version 2 of the License.
2.11 + *
2.12 + * This program is distributed in the hope that it will be useful,
2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.15 + * GNU General Public License for more details.
2.16 + *
2.17 + * You should have received a copy of the GNU General Public License
2.18 + * along with this program. Look for COPYING file in the top folder.
2.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
2.20 + */
2.21 +package org.apidesign.bck2brwsr.tck;
2.22 +
2.23 +import java.lang.reflect.InvocationHandler;
2.24 +import java.lang.reflect.Method;
2.25 +import java.lang.reflect.Proxy;
2.26 +import org.apidesign.bck2brwsr.vmtest.Compare;
2.27 +import org.apidesign.bck2brwsr.vmtest.VMTest;
2.28 +import org.testng.annotations.Factory;
2.29 +
2.30 +/**
2.31 + *
2.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
2.33 + */
2.34 +public class ProxyTest {
2.35 + @Compare public String generateAnnotation() throws Exception {
2.36 + class InvHandler implements InvocationHandler {
2.37 + @Override
2.38 + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
2.39 + return "Joe Hacker";
2.40 + }
2.41 + }
2.42 + Anno anno = (Anno) Proxy.newProxyInstance(
2.43 + Anno.class.getClassLoader(),
2.44 + new Class[] { Anno.class },
2.45 + new InvHandler()
2.46 + );
2.47 + return anno.name();
2.48 + }
2.49 +
2.50 + @Compare public int getPrimitiveType() throws Exception {
2.51 + class InvHandler implements InvocationHandler {
2.52 + @Override
2.53 + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
2.54 + return 40;
2.55 + }
2.56 + }
2.57 + Anno anno = (Anno) Proxy.newProxyInstance(
2.58 + Anno.class.getClassLoader(),
2.59 + new Class[] { Anno.class },
2.60 + new InvHandler()
2.61 + );
2.62 + return 2 + anno.age();
2.63 + }
2.64 +
2.65 + public static @interface Anno {
2.66 + public String name();
2.67 + public int age();
2.68 + }
2.69 +
2.70 + @Factory
2.71 + public static Object[] create() {
2.72 + return VMTest.create(ProxyTest.class);
2.73 + }
2.74 +}
3.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Proxy.java Mon Oct 21 12:02:43 2013 +0200
3.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Proxy.java Mon Oct 21 14:34:12 2013 +0200
3.3 @@ -212,7 +212,16 @@
3.4
3.5 private static final long serialVersionUID = -2222568056686623797L;
3.6
3.7 -
3.8 + private final static Method getProxyClass;
3.9 + static {
3.10 + Class<?> pg;
3.11 + try {
3.12 + pg = Class.forName("org.apidesign.bck2brwsr.emul.reflect.ProxyImpl");
3.13 + getProxyClass = pg.getMethod("getProxyClass", ClassLoader.class, Class[].class);
3.14 + } catch (Exception ex) {
3.15 + throw new IllegalStateException(ex);
3.16 + }
3.17 + }
3.18
3.19 /**
3.20 * the invocation handler for this proxy instance.
3.21 @@ -315,7 +324,14 @@
3.22 Class<?>... interfaces)
3.23 throws IllegalArgumentException
3.24 {
3.25 - throw new IllegalArgumentException();
3.26 + try {
3.27 + try { throw new IllegalArgumentException(); } catch (Throwable t) {}
3.28 + return (Class<?>) getProxyClass.invoke(null, loader, interfaces);
3.29 + } catch (IllegalAccessException ex) {
3.30 + throw new IllegalStateException(ex);
3.31 + } catch (InvocationTargetException ex) {
3.32 + throw (RuntimeException)ex.getTargetException();
3.33 + }
3.34 }
3.35
3.36 /**
3.37 @@ -355,7 +371,27 @@
3.38 if (h == null) {
3.39 throw new NullPointerException();
3.40 }
3.41 - throw new IllegalArgumentException();
3.42 +
3.43 + /*
3.44 + * Look up or generate the designated proxy class.
3.45 + */
3.46 + Class<?> cl = getProxyClass(loader, interfaces);
3.47 +
3.48 + /*
3.49 + * Invoke its constructor with the designated invocation handler.
3.50 + */
3.51 + try {
3.52 + Constructor cons = cl.getConstructor(InvocationHandler.class);
3.53 + return cons.newInstance(new Object[] { h });
3.54 + } catch (NoSuchMethodException e) {
3.55 + throw new IllegalStateException(e.toString());
3.56 + } catch (IllegalAccessException e) {
3.57 + throw new IllegalStateException(e.toString());
3.58 + } catch (InstantiationException e) {
3.59 + throw new IllegalStateException(e.toString());
3.60 + } catch (InvocationTargetException e) {
3.61 + throw new IllegalStateException(e.toString());
3.62 + }
3.63 }
3.64
3.65 /**
3.66 @@ -376,8 +412,7 @@
3.67 if (cl == null) {
3.68 throw new NullPointerException();
3.69 }
3.70 -
3.71 - return false;
3.72 + return Proxy.class.isAssignableFrom(cl);
3.73 }
3.74
3.75 /**
3.76 @@ -401,7 +436,4 @@
3.77 Proxy p = (Proxy) proxy;
3.78 return p.h;
3.79 }
3.80 -
3.81 - private static native Class defineClass0(ClassLoader loader, String name,
3.82 - byte[] b, int off, int len);
3.83 }