emul/mini/src/main/java/java/lang/reflect/Proxy.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 28 Jan 2013 18:12:47 +0100
branchjdk7-b147
changeset 601 5198affdb915
child 604 3fcc279c921b
permissions -rw-r--r--
Adding ObjectInputStream and ObjectOutputStream (but without implementation). Adding PropertyChange related classes.
jaroslav@601
     1
/*
jaroslav@601
     2
 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
jaroslav@601
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@601
     4
 *
jaroslav@601
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@601
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@601
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@601
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@601
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@601
    10
 *
jaroslav@601
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@601
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@601
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@601
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@601
    15
 * accompanied this code).
jaroslav@601
    16
 *
jaroslav@601
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@601
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@601
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@601
    20
 *
jaroslav@601
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@601
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@601
    23
 * questions.
jaroslav@601
    24
 */
jaroslav@601
    25
jaroslav@601
    26
package java.lang.reflect;
jaroslav@601
    27
jaroslav@601
    28
import java.lang.ref.Reference;
jaroslav@601
    29
import java.lang.ref.WeakReference;
jaroslav@601
    30
import java.util.Arrays;
jaroslav@601
    31
import java.util.Collections;
jaroslav@601
    32
import java.util.HashMap;
jaroslav@601
    33
import java.util.HashSet;
jaroslav@601
    34
import java.util.Map;
jaroslav@601
    35
import java.util.Set;
jaroslav@601
    36
import java.util.List;
jaroslav@601
    37
import java.util.WeakHashMap;
jaroslav@601
    38
import sun.misc.ProxyGenerator;
jaroslav@601
    39
jaroslav@601
    40
/**
jaroslav@601
    41
 * {@code Proxy} provides static methods for creating dynamic proxy
jaroslav@601
    42
 * classes and instances, and it is also the superclass of all
jaroslav@601
    43
 * dynamic proxy classes created by those methods.
jaroslav@601
    44
 *
jaroslav@601
    45
 * <p>To create a proxy for some interface {@code Foo}:
jaroslav@601
    46
 * <pre>
jaroslav@601
    47
 *     InvocationHandler handler = new MyInvocationHandler(...);
jaroslav@601
    48
 *     Class proxyClass = Proxy.getProxyClass(
jaroslav@601
    49
 *         Foo.class.getClassLoader(), new Class[] { Foo.class });
jaroslav@601
    50
 *     Foo f = (Foo) proxyClass.
jaroslav@601
    51
 *         getConstructor(new Class[] { InvocationHandler.class }).
jaroslav@601
    52
 *         newInstance(new Object[] { handler });
jaroslav@601
    53
 * </pre>
jaroslav@601
    54
 * or more simply:
jaroslav@601
    55
 * <pre>
jaroslav@601
    56
 *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
jaroslav@601
    57
 *                                          new Class[] { Foo.class },
jaroslav@601
    58
 *                                          handler);
jaroslav@601
    59
 * </pre>
jaroslav@601
    60
 *
jaroslav@601
    61
 * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
jaroslav@601
    62
 * class</i> below) is a class that implements a list of interfaces
jaroslav@601
    63
 * specified at runtime when the class is created, with behavior as
jaroslav@601
    64
 * described below.
jaroslav@601
    65
 *
jaroslav@601
    66
 * A <i>proxy interface</i> is such an interface that is implemented
jaroslav@601
    67
 * by a proxy class.
jaroslav@601
    68
 *
jaroslav@601
    69
 * A <i>proxy instance</i> is an instance of a proxy class.
jaroslav@601
    70
 *
jaroslav@601
    71
 * Each proxy instance has an associated <i>invocation handler</i>
jaroslav@601
    72
 * object, which implements the interface {@link InvocationHandler}.
jaroslav@601
    73
 * A method invocation on a proxy instance through one of its proxy
jaroslav@601
    74
 * interfaces will be dispatched to the {@link InvocationHandler#invoke
jaroslav@601
    75
 * invoke} method of the instance's invocation handler, passing the proxy
jaroslav@601
    76
 * instance, a {@code java.lang.reflect.Method} object identifying
jaroslav@601
    77
 * the method that was invoked, and an array of type {@code Object}
jaroslav@601
    78
 * containing the arguments.  The invocation handler processes the
jaroslav@601
    79
 * encoded method invocation as appropriate and the result that it
jaroslav@601
    80
 * returns will be returned as the result of the method invocation on
jaroslav@601
    81
 * the proxy instance.
jaroslav@601
    82
 *
jaroslav@601
    83
 * <p>A proxy class has the following properties:
jaroslav@601
    84
 *
jaroslav@601
    85
 * <ul>
jaroslav@601
    86
 * <li>Proxy classes are public, final, and not abstract.
jaroslav@601
    87
 *
jaroslav@601
    88
 * <li>The unqualified name of a proxy class is unspecified.  The space
jaroslav@601
    89
 * of class names that begin with the string {@code "$Proxy"}
jaroslav@601
    90
 * should be, however, reserved for proxy classes.
jaroslav@601
    91
 *
jaroslav@601
    92
 * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
jaroslav@601
    93
 *
jaroslav@601
    94
 * <li>A proxy class implements exactly the interfaces specified at its
jaroslav@601
    95
 * creation, in the same order.
jaroslav@601
    96
 *
jaroslav@601
    97
 * <li>If a proxy class implements a non-public interface, then it will
jaroslav@601
    98
 * be defined in the same package as that interface.  Otherwise, the
jaroslav@601
    99
 * package of a proxy class is also unspecified.  Note that package
jaroslav@601
   100
 * sealing will not prevent a proxy class from being successfully defined
jaroslav@601
   101
 * in a particular package at runtime, and neither will classes already
jaroslav@601
   102
 * defined by the same class loader and the same package with particular
jaroslav@601
   103
 * signers.
jaroslav@601
   104
 *
jaroslav@601
   105
 * <li>Since a proxy class implements all of the interfaces specified at
jaroslav@601
   106
 * its creation, invoking {@code getInterfaces} on its
jaroslav@601
   107
 * {@code Class} object will return an array containing the same
jaroslav@601
   108
 * list of interfaces (in the order specified at its creation), invoking
jaroslav@601
   109
 * {@code getMethods} on its {@code Class} object will return
jaroslav@601
   110
 * an array of {@code Method} objects that include all of the
jaroslav@601
   111
 * methods in those interfaces, and invoking {@code getMethod} will
jaroslav@601
   112
 * find methods in the proxy interfaces as would be expected.
jaroslav@601
   113
 *
jaroslav@601
   114
 * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
jaroslav@601
   115
 * return true if it is passed a proxy class-- a class returned by
jaroslav@601
   116
 * {@code Proxy.getProxyClass} or the class of an object returned by
jaroslav@601
   117
 * {@code Proxy.newProxyInstance}-- and false otherwise.
jaroslav@601
   118
 *
jaroslav@601
   119
 * <li>The {@code java.security.ProtectionDomain} of a proxy class
jaroslav@601
   120
 * is the same as that of system classes loaded by the bootstrap class
jaroslav@601
   121
 * loader, such as {@code java.lang.Object}, because the code for a
jaroslav@601
   122
 * proxy class is generated by trusted system code.  This protection
jaroslav@601
   123
 * domain will typically be granted
jaroslav@601
   124
 * {@code java.security.AllPermission}.
jaroslav@601
   125
 *
jaroslav@601
   126
 * <li>Each proxy class has one public constructor that takes one argument,
jaroslav@601
   127
 * an implementation of the interface {@link InvocationHandler}, to set
jaroslav@601
   128
 * the invocation handler for a proxy instance.  Rather than having to use
jaroslav@601
   129
 * the reflection API to access the public constructor, a proxy instance
jaroslav@601
   130
 * can be also be created by calling the {@link Proxy#newProxyInstance
jaroslav@601
   131
 * Proxy.newProxyInstance} method, which combines the actions of calling
jaroslav@601
   132
 * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
jaroslav@601
   133
 * constructor with an invocation handler.
jaroslav@601
   134
 * </ul>
jaroslav@601
   135
 *
jaroslav@601
   136
 * <p>A proxy instance has the following properties:
jaroslav@601
   137
 *
jaroslav@601
   138
 * <ul>
jaroslav@601
   139
 * <li>Given a proxy instance {@code proxy} and one of the
jaroslav@601
   140
 * interfaces implemented by its proxy class {@code Foo}, the
jaroslav@601
   141
 * following expression will return true:
jaroslav@601
   142
 * <pre>
jaroslav@601
   143
 *     {@code proxy instanceof Foo}
jaroslav@601
   144
 * </pre>
jaroslav@601
   145
 * and the following cast operation will succeed (rather than throwing
jaroslav@601
   146
 * a {@code ClassCastException}):
jaroslav@601
   147
 * <pre>
jaroslav@601
   148
 *     {@code (Foo) proxy}
jaroslav@601
   149
 * </pre>
jaroslav@601
   150
 *
jaroslav@601
   151
 * <li>Each proxy instance has an associated invocation handler, the one
jaroslav@601
   152
 * that was passed to its constructor.  The static
jaroslav@601
   153
 * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method
jaroslav@601
   154
 * will return the invocation handler associated with the proxy instance
jaroslav@601
   155
 * passed as its argument.
jaroslav@601
   156
 *
jaroslav@601
   157
 * <li>An interface method invocation on a proxy instance will be
jaroslav@601
   158
 * encoded and dispatched to the invocation handler's {@link
jaroslav@601
   159
 * InvocationHandler#invoke invoke} method as described in the
jaroslav@601
   160
 * documentation for that method.
jaroslav@601
   161
 *
jaroslav@601
   162
 * <li>An invocation of the {@code hashCode},
jaroslav@601
   163
 * {@code equals}, or {@code toString} methods declared in
jaroslav@601
   164
 * {@code java.lang.Object} on a proxy instance will be encoded and
jaroslav@601
   165
 * dispatched to the invocation handler's {@code invoke} method in
jaroslav@601
   166
 * the same manner as interface method invocations are encoded and
jaroslav@601
   167
 * dispatched, as described above.  The declaring class of the
jaroslav@601
   168
 * {@code Method} object passed to {@code invoke} will be
jaroslav@601
   169
 * {@code java.lang.Object}.  Other public methods of a proxy
jaroslav@601
   170
 * instance inherited from {@code java.lang.Object} are not
jaroslav@601
   171
 * overridden by a proxy class, so invocations of those methods behave
jaroslav@601
   172
 * like they do for instances of {@code java.lang.Object}.
jaroslav@601
   173
 * </ul>
jaroslav@601
   174
 *
jaroslav@601
   175
 * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
jaroslav@601
   176
 *
jaroslav@601
   177
 * <p>When two or more interfaces of a proxy class contain a method with
jaroslav@601
   178
 * the same name and parameter signature, the order of the proxy class's
jaroslav@601
   179
 * interfaces becomes significant.  When such a <i>duplicate method</i>
jaroslav@601
   180
 * is invoked on a proxy instance, the {@code Method} object passed
jaroslav@601
   181
 * to the invocation handler will not necessarily be the one whose
jaroslav@601
   182
 * declaring class is assignable from the reference type of the interface
jaroslav@601
   183
 * that the proxy's method was invoked through.  This limitation exists
jaroslav@601
   184
 * because the corresponding method implementation in the generated proxy
jaroslav@601
   185
 * class cannot determine which interface it was invoked through.
jaroslav@601
   186
 * Therefore, when a duplicate method is invoked on a proxy instance,
jaroslav@601
   187
 * the {@code Method} object for the method in the foremost interface
jaroslav@601
   188
 * that contains the method (either directly or inherited through a
jaroslav@601
   189
 * superinterface) in the proxy class's list of interfaces is passed to
jaroslav@601
   190
 * the invocation handler's {@code invoke} method, regardless of the
jaroslav@601
   191
 * reference type through which the method invocation occurred.
jaroslav@601
   192
 *
jaroslav@601
   193
 * <p>If a proxy interface contains a method with the same name and
jaroslav@601
   194
 * parameter signature as the {@code hashCode}, {@code equals},
jaroslav@601
   195
 * or {@code toString} methods of {@code java.lang.Object},
jaroslav@601
   196
 * when such a method is invoked on a proxy instance, the
jaroslav@601
   197
 * {@code Method} object passed to the invocation handler will have
jaroslav@601
   198
 * {@code java.lang.Object} as its declaring class.  In other words,
jaroslav@601
   199
 * the public, non-final methods of {@code java.lang.Object}
jaroslav@601
   200
 * logically precede all of the proxy interfaces for the determination of
jaroslav@601
   201
 * which {@code Method} object to pass to the invocation handler.
jaroslav@601
   202
 *
jaroslav@601
   203
 * <p>Note also that when a duplicate method is dispatched to an
jaroslav@601
   204
 * invocation handler, the {@code invoke} method may only throw
jaroslav@601
   205
 * checked exception types that are assignable to one of the exception
jaroslav@601
   206
 * types in the {@code throws} clause of the method in <i>all</i> of
jaroslav@601
   207
 * the proxy interfaces that it can be invoked through.  If the
jaroslav@601
   208
 * {@code invoke} method throws a checked exception that is not
jaroslav@601
   209
 * assignable to any of the exception types declared by the method in one
jaroslav@601
   210
 * of the proxy interfaces that it can be invoked through, then an
jaroslav@601
   211
 * unchecked {@code UndeclaredThrowableException} will be thrown by
jaroslav@601
   212
 * the invocation on the proxy instance.  This restriction means that not
jaroslav@601
   213
 * all of the exception types returned by invoking
jaroslav@601
   214
 * {@code getExceptionTypes} on the {@code Method} object
jaroslav@601
   215
 * passed to the {@code invoke} method can necessarily be thrown
jaroslav@601
   216
 * successfully by the {@code invoke} method.
jaroslav@601
   217
 *
jaroslav@601
   218
 * @author      Peter Jones
jaroslav@601
   219
 * @see         InvocationHandler
jaroslav@601
   220
 * @since       1.3
jaroslav@601
   221
 */
jaroslav@601
   222
public class Proxy implements java.io.Serializable {
jaroslav@601
   223
jaroslav@601
   224
    private static final long serialVersionUID = -2222568056686623797L;
jaroslav@601
   225
jaroslav@601
   226
    /** prefix for all proxy class names */
jaroslav@601
   227
    private final static String proxyClassNamePrefix = "$Proxy";
jaroslav@601
   228
jaroslav@601
   229
    /** parameter types of a proxy class constructor */
jaroslav@601
   230
    private final static Class[] constructorParams =
jaroslav@601
   231
        { InvocationHandler.class };
jaroslav@601
   232
jaroslav@601
   233
    /** maps a class loader to the proxy class cache for that loader */
jaroslav@601
   234
    private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
jaroslav@601
   235
        = new WeakHashMap<>();
jaroslav@601
   236
jaroslav@601
   237
    /** marks that a particular proxy class is currently being generated */
jaroslav@601
   238
    private static Object pendingGenerationMarker = new Object();
jaroslav@601
   239
jaroslav@601
   240
    /** next number to use for generation of unique proxy class names */
jaroslav@601
   241
    private static long nextUniqueNumber = 0;
jaroslav@601
   242
    private static Object nextUniqueNumberLock = new Object();
jaroslav@601
   243
jaroslav@601
   244
    /** set of all generated proxy classes, for isProxyClass implementation */
jaroslav@601
   245
    private static Map<Class<?>, Void> proxyClasses =
jaroslav@601
   246
        Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
jaroslav@601
   247
jaroslav@601
   248
    /**
jaroslav@601
   249
     * the invocation handler for this proxy instance.
jaroslav@601
   250
     * @serial
jaroslav@601
   251
     */
jaroslav@601
   252
    protected InvocationHandler h;
jaroslav@601
   253
jaroslav@601
   254
    /**
jaroslav@601
   255
     * Prohibits instantiation.
jaroslav@601
   256
     */
jaroslav@601
   257
    private Proxy() {
jaroslav@601
   258
    }
jaroslav@601
   259
jaroslav@601
   260
    /**
jaroslav@601
   261
     * Constructs a new {@code Proxy} instance from a subclass
jaroslav@601
   262
     * (typically, a dynamic proxy class) with the specified value
jaroslav@601
   263
     * for its invocation handler.
jaroslav@601
   264
     *
jaroslav@601
   265
     * @param   h the invocation handler for this proxy instance
jaroslav@601
   266
     */
jaroslav@601
   267
    protected Proxy(InvocationHandler h) {
jaroslav@601
   268
        this.h = h;
jaroslav@601
   269
    }
jaroslav@601
   270
jaroslav@601
   271
    /**
jaroslav@601
   272
     * Returns the {@code java.lang.Class} object for a proxy class
jaroslav@601
   273
     * given a class loader and an array of interfaces.  The proxy class
jaroslav@601
   274
     * will be defined by the specified class loader and will implement
jaroslav@601
   275
     * all of the supplied interfaces.  If a proxy class for the same
jaroslav@601
   276
     * permutation of interfaces has already been defined by the class
jaroslav@601
   277
     * loader, then the existing proxy class will be returned; otherwise,
jaroslav@601
   278
     * a proxy class for those interfaces will be generated dynamically
jaroslav@601
   279
     * and defined by the class loader.
jaroslav@601
   280
     *
jaroslav@601
   281
     * <p>There are several restrictions on the parameters that may be
jaroslav@601
   282
     * passed to {@code Proxy.getProxyClass}:
jaroslav@601
   283
     *
jaroslav@601
   284
     * <ul>
jaroslav@601
   285
     * <li>All of the {@code Class} objects in the
jaroslav@601
   286
     * {@code interfaces} array must represent interfaces, not
jaroslav@601
   287
     * classes or primitive types.
jaroslav@601
   288
     *
jaroslav@601
   289
     * <li>No two elements in the {@code interfaces} array may
jaroslav@601
   290
     * refer to identical {@code Class} objects.
jaroslav@601
   291
     *
jaroslav@601
   292
     * <li>All of the interface types must be visible by name through the
jaroslav@601
   293
     * specified class loader.  In other words, for class loader
jaroslav@601
   294
     * {@code cl} and every interface {@code i}, the following
jaroslav@601
   295
     * expression must be true:
jaroslav@601
   296
     * <pre>
jaroslav@601
   297
     *     Class.forName(i.getName(), false, cl) == i
jaroslav@601
   298
     * </pre>
jaroslav@601
   299
     *
jaroslav@601
   300
     * <li>All non-public interfaces must be in the same package;
jaroslav@601
   301
     * otherwise, it would not be possible for the proxy class to
jaroslav@601
   302
     * implement all of the interfaces, regardless of what package it is
jaroslav@601
   303
     * defined in.
jaroslav@601
   304
     *
jaroslav@601
   305
     * <li>For any set of member methods of the specified interfaces
jaroslav@601
   306
     * that have the same signature:
jaroslav@601
   307
     * <ul>
jaroslav@601
   308
     * <li>If the return type of any of the methods is a primitive
jaroslav@601
   309
     * type or void, then all of the methods must have that same
jaroslav@601
   310
     * return type.
jaroslav@601
   311
     * <li>Otherwise, one of the methods must have a return type that
jaroslav@601
   312
     * is assignable to all of the return types of the rest of the
jaroslav@601
   313
     * methods.
jaroslav@601
   314
     * </ul>
jaroslav@601
   315
     *
jaroslav@601
   316
     * <li>The resulting proxy class must not exceed any limits imposed
jaroslav@601
   317
     * on classes by the virtual machine.  For example, the VM may limit
jaroslav@601
   318
     * the number of interfaces that a class may implement to 65535; in
jaroslav@601
   319
     * that case, the size of the {@code interfaces} array must not
jaroslav@601
   320
     * exceed 65535.
jaroslav@601
   321
     * </ul>
jaroslav@601
   322
     *
jaroslav@601
   323
     * <p>If any of these restrictions are violated,
jaroslav@601
   324
     * {@code Proxy.getProxyClass} will throw an
jaroslav@601
   325
     * {@code IllegalArgumentException}.  If the {@code interfaces}
jaroslav@601
   326
     * array argument or any of its elements are {@code null}, a
jaroslav@601
   327
     * {@code NullPointerException} will be thrown.
jaroslav@601
   328
     *
jaroslav@601
   329
     * <p>Note that the order of the specified proxy interfaces is
jaroslav@601
   330
     * significant: two requests for a proxy class with the same combination
jaroslav@601
   331
     * of interfaces but in a different order will result in two distinct
jaroslav@601
   332
     * proxy classes.
jaroslav@601
   333
     *
jaroslav@601
   334
     * @param   loader the class loader to define the proxy class
jaroslav@601
   335
     * @param   interfaces the list of interfaces for the proxy class
jaroslav@601
   336
     *          to implement
jaroslav@601
   337
     * @return  a proxy class that is defined in the specified class loader
jaroslav@601
   338
     *          and that implements the specified interfaces
jaroslav@601
   339
     * @throws  IllegalArgumentException if any of the restrictions on the
jaroslav@601
   340
     *          parameters that may be passed to {@code getProxyClass}
jaroslav@601
   341
     *          are violated
jaroslav@601
   342
     * @throws  NullPointerException if the {@code interfaces} array
jaroslav@601
   343
     *          argument or any of its elements are {@code null}
jaroslav@601
   344
     */
jaroslav@601
   345
    public static Class<?> getProxyClass(ClassLoader loader,
jaroslav@601
   346
                                         Class<?>... interfaces)
jaroslav@601
   347
        throws IllegalArgumentException
jaroslav@601
   348
    {
jaroslav@601
   349
        if (interfaces.length > 65535) {
jaroslav@601
   350
            throw new IllegalArgumentException("interface limit exceeded");
jaroslav@601
   351
        }
jaroslav@601
   352
jaroslav@601
   353
        Class<?> proxyClass = null;
jaroslav@601
   354
jaroslav@601
   355
        /* collect interface names to use as key for proxy class cache */
jaroslav@601
   356
        String[] interfaceNames = new String[interfaces.length];
jaroslav@601
   357
jaroslav@601
   358
        // for detecting duplicates
jaroslav@601
   359
        Set<Class<?>> interfaceSet = new HashSet<>();
jaroslav@601
   360
jaroslav@601
   361
        for (int i = 0; i < interfaces.length; i++) {
jaroslav@601
   362
            /*
jaroslav@601
   363
             * Verify that the class loader resolves the name of this
jaroslav@601
   364
             * interface to the same Class object.
jaroslav@601
   365
             */
jaroslav@601
   366
            String interfaceName = interfaces[i].getName();
jaroslav@601
   367
            Class<?> interfaceClass = null;
jaroslav@601
   368
            try {
jaroslav@601
   369
                interfaceClass = Class.forName(interfaceName, false, loader);
jaroslav@601
   370
            } catch (ClassNotFoundException e) {
jaroslav@601
   371
            }
jaroslav@601
   372
            if (interfaceClass != interfaces[i]) {
jaroslav@601
   373
                throw new IllegalArgumentException(
jaroslav@601
   374
                    interfaces[i] + " is not visible from class loader");
jaroslav@601
   375
            }
jaroslav@601
   376
jaroslav@601
   377
            /*
jaroslav@601
   378
             * Verify that the Class object actually represents an
jaroslav@601
   379
             * interface.
jaroslav@601
   380
             */
jaroslav@601
   381
            if (!interfaceClass.isInterface()) {
jaroslav@601
   382
                throw new IllegalArgumentException(
jaroslav@601
   383
                    interfaceClass.getName() + " is not an interface");
jaroslav@601
   384
            }
jaroslav@601
   385
jaroslav@601
   386
            /*
jaroslav@601
   387
             * Verify that this interface is not a duplicate.
jaroslav@601
   388
             */
jaroslav@601
   389
            if (interfaceSet.contains(interfaceClass)) {
jaroslav@601
   390
                throw new IllegalArgumentException(
jaroslav@601
   391
                    "repeated interface: " + interfaceClass.getName());
jaroslav@601
   392
            }
jaroslav@601
   393
            interfaceSet.add(interfaceClass);
jaroslav@601
   394
jaroslav@601
   395
            interfaceNames[i] = interfaceName;
jaroslav@601
   396
        }
jaroslav@601
   397
jaroslav@601
   398
        /*
jaroslav@601
   399
         * Using string representations of the proxy interfaces as
jaroslav@601
   400
         * keys in the proxy class cache (instead of their Class
jaroslav@601
   401
         * objects) is sufficient because we require the proxy
jaroslav@601
   402
         * interfaces to be resolvable by name through the supplied
jaroslav@601
   403
         * class loader, and it has the advantage that using a string
jaroslav@601
   404
         * representation of a class makes for an implicit weak
jaroslav@601
   405
         * reference to the class.
jaroslav@601
   406
         */
jaroslav@601
   407
        List<String> key = Arrays.asList(interfaceNames);
jaroslav@601
   408
jaroslav@601
   409
        /*
jaroslav@601
   410
         * Find or create the proxy class cache for the class loader.
jaroslav@601
   411
         */
jaroslav@601
   412
        Map<List<String>, Object> cache;
jaroslav@601
   413
        synchronized (loaderToCache) {
jaroslav@601
   414
            cache = loaderToCache.get(loader);
jaroslav@601
   415
            if (cache == null) {
jaroslav@601
   416
                cache = new HashMap<>();
jaroslav@601
   417
                loaderToCache.put(loader, cache);
jaroslav@601
   418
            }
jaroslav@601
   419
            /*
jaroslav@601
   420
             * This mapping will remain valid for the duration of this
jaroslav@601
   421
             * method, without further synchronization, because the mapping
jaroslav@601
   422
             * will only be removed if the class loader becomes unreachable.
jaroslav@601
   423
             */
jaroslav@601
   424
        }
jaroslav@601
   425
jaroslav@601
   426
        /*
jaroslav@601
   427
         * Look up the list of interfaces in the proxy class cache using
jaroslav@601
   428
         * the key.  This lookup will result in one of three possible
jaroslav@601
   429
         * kinds of values:
jaroslav@601
   430
         *     null, if there is currently no proxy class for the list of
jaroslav@601
   431
         *         interfaces in the class loader,
jaroslav@601
   432
         *     the pendingGenerationMarker object, if a proxy class for the
jaroslav@601
   433
         *         list of interfaces is currently being generated,
jaroslav@601
   434
         *     or a weak reference to a Class object, if a proxy class for
jaroslav@601
   435
         *         the list of interfaces has already been generated.
jaroslav@601
   436
         */
jaroslav@601
   437
        synchronized (cache) {
jaroslav@601
   438
            /*
jaroslav@601
   439
             * Note that we need not worry about reaping the cache for
jaroslav@601
   440
             * entries with cleared weak references because if a proxy class
jaroslav@601
   441
             * has been garbage collected, its class loader will have been
jaroslav@601
   442
             * garbage collected as well, so the entire cache will be reaped
jaroslav@601
   443
             * from the loaderToCache map.
jaroslav@601
   444
             */
jaroslav@601
   445
            do {
jaroslav@601
   446
                Object value = cache.get(key);
jaroslav@601
   447
                if (value instanceof Reference) {
jaroslav@601
   448
                    proxyClass = (Class<?>) ((Reference) value).get();
jaroslav@601
   449
                }
jaroslav@601
   450
                if (proxyClass != null) {
jaroslav@601
   451
                    // proxy class already generated: return it
jaroslav@601
   452
                    return proxyClass;
jaroslav@601
   453
                } else if (value == pendingGenerationMarker) {
jaroslav@601
   454
                    // proxy class being generated: wait for it
jaroslav@601
   455
                    try {
jaroslav@601
   456
                        cache.wait();
jaroslav@601
   457
                    } catch (InterruptedException e) {
jaroslav@601
   458
                        /*
jaroslav@601
   459
                         * The class generation that we are waiting for should
jaroslav@601
   460
                         * take a small, bounded time, so we can safely ignore
jaroslav@601
   461
                         * thread interrupts here.
jaroslav@601
   462
                         */
jaroslav@601
   463
                    }
jaroslav@601
   464
                    continue;
jaroslav@601
   465
                } else {
jaroslav@601
   466
                    /*
jaroslav@601
   467
                     * No proxy class for this list of interfaces has been
jaroslav@601
   468
                     * generated or is being generated, so we will go and
jaroslav@601
   469
                     * generate it now.  Mark it as pending generation.
jaroslav@601
   470
                     */
jaroslav@601
   471
                    cache.put(key, pendingGenerationMarker);
jaroslav@601
   472
                    break;
jaroslav@601
   473
                }
jaroslav@601
   474
            } while (true);
jaroslav@601
   475
        }
jaroslav@601
   476
jaroslav@601
   477
        try {
jaroslav@601
   478
            String proxyPkg = null;     // package to define proxy class in
jaroslav@601
   479
jaroslav@601
   480
            /*
jaroslav@601
   481
             * Record the package of a non-public proxy interface so that the
jaroslav@601
   482
             * proxy class will be defined in the same package.  Verify that
jaroslav@601
   483
             * all non-public proxy interfaces are in the same package.
jaroslav@601
   484
             */
jaroslav@601
   485
            for (int i = 0; i < interfaces.length; i++) {
jaroslav@601
   486
                int flags = interfaces[i].getModifiers();
jaroslav@601
   487
                if (!Modifier.isPublic(flags)) {
jaroslav@601
   488
                    String name = interfaces[i].getName();
jaroslav@601
   489
                    int n = name.lastIndexOf('.');
jaroslav@601
   490
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
jaroslav@601
   491
                    if (proxyPkg == null) {
jaroslav@601
   492
                        proxyPkg = pkg;
jaroslav@601
   493
                    } else if (!pkg.equals(proxyPkg)) {
jaroslav@601
   494
                        throw new IllegalArgumentException(
jaroslav@601
   495
                            "non-public interfaces from different packages");
jaroslav@601
   496
                    }
jaroslav@601
   497
                }
jaroslav@601
   498
            }
jaroslav@601
   499
jaroslav@601
   500
            if (proxyPkg == null) {     // if no non-public proxy interfaces,
jaroslav@601
   501
                proxyPkg = "";          // use the unnamed package
jaroslav@601
   502
            }
jaroslav@601
   503
jaroslav@601
   504
            {
jaroslav@601
   505
                /*
jaroslav@601
   506
                 * Choose a name for the proxy class to generate.
jaroslav@601
   507
                 */
jaroslav@601
   508
                long num;
jaroslav@601
   509
                synchronized (nextUniqueNumberLock) {
jaroslav@601
   510
                    num = nextUniqueNumber++;
jaroslav@601
   511
                }
jaroslav@601
   512
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
jaroslav@601
   513
                /*
jaroslav@601
   514
                 * Verify that the class loader hasn't already
jaroslav@601
   515
                 * defined a class with the chosen name.
jaroslav@601
   516
                 */
jaroslav@601
   517
jaroslav@601
   518
                /*
jaroslav@601
   519
                 * Generate the specified proxy class.
jaroslav@601
   520
                 */
jaroslav@601
   521
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
jaroslav@601
   522
                    proxyName, interfaces);
jaroslav@601
   523
                try {
jaroslav@601
   524
                    proxyClass = defineClass0(loader, proxyName,
jaroslav@601
   525
                        proxyClassFile, 0, proxyClassFile.length);
jaroslav@601
   526
                } catch (ClassFormatError e) {
jaroslav@601
   527
                    /*
jaroslav@601
   528
                     * A ClassFormatError here means that (barring bugs in the
jaroslav@601
   529
                     * proxy class generation code) there was some other
jaroslav@601
   530
                     * invalid aspect of the arguments supplied to the proxy
jaroslav@601
   531
                     * class creation (such as virtual machine limitations
jaroslav@601
   532
                     * exceeded).
jaroslav@601
   533
                     */
jaroslav@601
   534
                    throw new IllegalArgumentException(e.toString());
jaroslav@601
   535
                }
jaroslav@601
   536
            }
jaroslav@601
   537
            // add to set of all generated proxy classes, for isProxyClass
jaroslav@601
   538
            proxyClasses.put(proxyClass, null);
jaroslav@601
   539
jaroslav@601
   540
        } finally {
jaroslav@601
   541
            /*
jaroslav@601
   542
             * We must clean up the "pending generation" state of the proxy
jaroslav@601
   543
             * class cache entry somehow.  If a proxy class was successfully
jaroslav@601
   544
             * generated, store it in the cache (with a weak reference);
jaroslav@601
   545
             * otherwise, remove the reserved entry.  In all cases, notify
jaroslav@601
   546
             * all waiters on reserved entries in this cache.
jaroslav@601
   547
             */
jaroslav@601
   548
            synchronized (cache) {
jaroslav@601
   549
                if (proxyClass != null) {
jaroslav@601
   550
                    cache.put(key, new WeakReference<Class<?>>(proxyClass));
jaroslav@601
   551
                } else {
jaroslav@601
   552
                    cache.remove(key);
jaroslav@601
   553
                }
jaroslav@601
   554
                cache.notifyAll();
jaroslav@601
   555
            }
jaroslav@601
   556
        }
jaroslav@601
   557
        return proxyClass;
jaroslav@601
   558
    }
jaroslav@601
   559
jaroslav@601
   560
    /**
jaroslav@601
   561
     * Returns an instance of a proxy class for the specified interfaces
jaroslav@601
   562
     * that dispatches method invocations to the specified invocation
jaroslav@601
   563
     * handler.  This method is equivalent to:
jaroslav@601
   564
     * <pre>
jaroslav@601
   565
     *     Proxy.getProxyClass(loader, interfaces).
jaroslav@601
   566
     *         getConstructor(new Class[] { InvocationHandler.class }).
jaroslav@601
   567
     *         newInstance(new Object[] { handler });
jaroslav@601
   568
     * </pre>
jaroslav@601
   569
     *
jaroslav@601
   570
     * <p>{@code Proxy.newProxyInstance} throws
jaroslav@601
   571
     * {@code IllegalArgumentException} for the same reasons that
jaroslav@601
   572
     * {@code Proxy.getProxyClass} does.
jaroslav@601
   573
     *
jaroslav@601
   574
     * @param   loader the class loader to define the proxy class
jaroslav@601
   575
     * @param   interfaces the list of interfaces for the proxy class
jaroslav@601
   576
     *          to implement
jaroslav@601
   577
     * @param   h the invocation handler to dispatch method invocations to
jaroslav@601
   578
     * @return  a proxy instance with the specified invocation handler of a
jaroslav@601
   579
     *          proxy class that is defined by the specified class loader
jaroslav@601
   580
     *          and that implements the specified interfaces
jaroslav@601
   581
     * @throws  IllegalArgumentException if any of the restrictions on the
jaroslav@601
   582
     *          parameters that may be passed to {@code getProxyClass}
jaroslav@601
   583
     *          are violated
jaroslav@601
   584
     * @throws  NullPointerException if the {@code interfaces} array
jaroslav@601
   585
     *          argument or any of its elements are {@code null}, or
jaroslav@601
   586
     *          if the invocation handler, {@code h}, is
jaroslav@601
   587
     *          {@code null}
jaroslav@601
   588
     */
jaroslav@601
   589
    public static Object newProxyInstance(ClassLoader loader,
jaroslav@601
   590
                                          Class<?>[] interfaces,
jaroslav@601
   591
                                          InvocationHandler h)
jaroslav@601
   592
        throws IllegalArgumentException
jaroslav@601
   593
    {
jaroslav@601
   594
        if (h == null) {
jaroslav@601
   595
            throw new NullPointerException();
jaroslav@601
   596
        }
jaroslav@601
   597
jaroslav@601
   598
        /*
jaroslav@601
   599
         * Look up or generate the designated proxy class.
jaroslav@601
   600
         */
jaroslav@601
   601
        Class<?> cl = getProxyClass(loader, interfaces);
jaroslav@601
   602
jaroslav@601
   603
        /*
jaroslav@601
   604
         * Invoke its constructor with the designated invocation handler.
jaroslav@601
   605
         */
jaroslav@601
   606
        try {
jaroslav@601
   607
            Constructor cons = cl.getConstructor(constructorParams);
jaroslav@601
   608
            return cons.newInstance(new Object[] { h });
jaroslav@601
   609
        } catch (NoSuchMethodException e) {
jaroslav@601
   610
            throw new InternalError(e.toString());
jaroslav@601
   611
        } catch (IllegalAccessException e) {
jaroslav@601
   612
            throw new InternalError(e.toString());
jaroslav@601
   613
        } catch (InstantiationException e) {
jaroslav@601
   614
            throw new InternalError(e.toString());
jaroslav@601
   615
        } catch (InvocationTargetException e) {
jaroslav@601
   616
            throw new InternalError(e.toString());
jaroslav@601
   617
        }
jaroslav@601
   618
    }
jaroslav@601
   619
jaroslav@601
   620
    /**
jaroslav@601
   621
     * Returns true if and only if the specified class was dynamically
jaroslav@601
   622
     * generated to be a proxy class using the {@code getProxyClass}
jaroslav@601
   623
     * method or the {@code newProxyInstance} method.
jaroslav@601
   624
     *
jaroslav@601
   625
     * <p>The reliability of this method is important for the ability
jaroslav@601
   626
     * to use it to make security decisions, so its implementation should
jaroslav@601
   627
     * not just test if the class in question extends {@code Proxy}.
jaroslav@601
   628
     *
jaroslav@601
   629
     * @param   cl the class to test
jaroslav@601
   630
     * @return  {@code true} if the class is a proxy class and
jaroslav@601
   631
     *          {@code false} otherwise
jaroslav@601
   632
     * @throws  NullPointerException if {@code cl} is {@code null}
jaroslav@601
   633
     */
jaroslav@601
   634
    public static boolean isProxyClass(Class<?> cl) {
jaroslav@601
   635
        if (cl == null) {
jaroslav@601
   636
            throw new NullPointerException();
jaroslav@601
   637
        }
jaroslav@601
   638
jaroslav@601
   639
        return proxyClasses.containsKey(cl);
jaroslav@601
   640
    }
jaroslav@601
   641
jaroslav@601
   642
    /**
jaroslav@601
   643
     * Returns the invocation handler for the specified proxy instance.
jaroslav@601
   644
     *
jaroslav@601
   645
     * @param   proxy the proxy instance to return the invocation handler for
jaroslav@601
   646
     * @return  the invocation handler for the proxy instance
jaroslav@601
   647
     * @throws  IllegalArgumentException if the argument is not a
jaroslav@601
   648
     *          proxy instance
jaroslav@601
   649
     */
jaroslav@601
   650
    public static InvocationHandler getInvocationHandler(Object proxy)
jaroslav@601
   651
        throws IllegalArgumentException
jaroslav@601
   652
    {
jaroslav@601
   653
        /*
jaroslav@601
   654
         * Verify that the object is actually a proxy instance.
jaroslav@601
   655
         */
jaroslav@601
   656
        if (!isProxyClass(proxy.getClass())) {
jaroslav@601
   657
            throw new IllegalArgumentException("not a proxy instance");
jaroslav@601
   658
        }
jaroslav@601
   659
jaroslav@601
   660
        Proxy p = (Proxy) proxy;
jaroslav@601
   661
        return p.h;
jaroslav@601
   662
    }
jaroslav@601
   663
jaroslav@601
   664
    private static native Class defineClass0(ClassLoader loader, String name,
jaroslav@601
   665
                                             byte[] b, int off, int len);
jaroslav@601
   666
}