jdk/src/share/classes/java/lang/reflect/Proxy.java
changeset 17188 5e58e261911b
parent 16923 50bfa0defec2
child 17497 e65d73b7ae54
child 18249 aec7e8963c3e
equal deleted inserted replaced
17187:692bf32a1f26 17188:5e58e261911b
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package java.lang.reflect;
    26 package java.lang.reflect;
    27 
    27 
    28 import java.lang.ref.Reference;
       
    29 import java.lang.ref.WeakReference;
    28 import java.lang.ref.WeakReference;
    30 import java.security.AccessController;
    29 import java.security.AccessController;
    31 import java.security.PrivilegedAction;
    30 import java.security.PrivilegedAction;
    32 import java.util.Arrays;
    31 import java.util.Arrays;
    33 import java.util.Collections;
    32 import java.util.IdentityHashMap;
    34 import java.util.HashMap;
       
    35 import java.util.HashSet;
       
    36 import java.util.Map;
    33 import java.util.Map;
    37 import java.util.Set;
    34 import java.util.concurrent.atomic.AtomicLong;
    38 import java.util.List;
    35 import java.util.function.BiFunction;
    39 import java.util.WeakHashMap;
       
    40 import sun.misc.ProxyGenerator;
    36 import sun.misc.ProxyGenerator;
    41 import sun.misc.VM;
    37 import sun.misc.VM;
    42 import sun.reflect.CallerSensitive;
    38 import sun.reflect.CallerSensitive;
    43 import sun.reflect.Reflection;
    39 import sun.reflect.Reflection;
    44 import sun.reflect.misc.ReflectUtil;
    40 import sun.reflect.misc.ReflectUtil;
   230  */
   226  */
   231 public class Proxy implements java.io.Serializable {
   227 public class Proxy implements java.io.Serializable {
   232 
   228 
   233     private static final long serialVersionUID = -2222568056686623797L;
   229     private static final long serialVersionUID = -2222568056686623797L;
   234 
   230 
   235     /** prefix for all proxy class names */
       
   236     private final static String proxyClassNamePrefix = "$Proxy";
       
   237 
       
   238     /** parameter types of a proxy class constructor */
   231     /** parameter types of a proxy class constructor */
   239     private final static Class[] constructorParams =
   232     private static final Class<?>[] constructorParams =
   240         { InvocationHandler.class };
   233         { InvocationHandler.class };
   241 
   234 
   242     /** maps a class loader to the proxy class cache for that loader */
   235     /**
   243     private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
   236      * a cache of proxy classes
   244         = new WeakHashMap<>();
   237      */
   245 
   238     private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
   246     /** marks that a particular proxy class is currently being generated */
   239         proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
   247     private static Object pendingGenerationMarker = new Object();
       
   248 
       
   249     /** next number to use for generation of unique proxy class names */
       
   250     private static long nextUniqueNumber = 0;
       
   251     private static Object nextUniqueNumberLock = new Object();
       
   252 
       
   253     /** set of all generated proxy classes, for isProxyClass implementation */
       
   254     private static Map<Class<?>, Void> proxyClasses =
       
   255         Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
       
   256 
   240 
   257     /**
   241     /**
   258      * the invocation handler for this proxy instance.
   242      * the invocation handler for this proxy instance.
   259      * @serial
   243      * @serial
   260      */
   244      */
   421                                            Class<?>... interfaces) {
   405                                            Class<?>... interfaces) {
   422         if (interfaces.length > 65535) {
   406         if (interfaces.length > 65535) {
   423             throw new IllegalArgumentException("interface limit exceeded");
   407             throw new IllegalArgumentException("interface limit exceeded");
   424         }
   408         }
   425 
   409 
   426         Class<?> proxyClass = null;
   410         // If the proxy class defined by the given loader implementing
   427 
   411         // the given interfaces exists, this will simply return the cached copy;
   428         /* collect interface names to use as key for proxy class cache */
   412         // otherwise, it will create the proxy class via the ProxyClassFactory
   429         String[] interfaceNames = new String[interfaces.length];
   413         return proxyClassCache.get(loader, interfaces);
   430 
   414     }
   431         // for detecting duplicates
   415 
   432         Set<Class<?>> interfaceSet = new HashSet<>();
   416     /*
   433 
   417      * a key used for proxy class with 0 implemented interfaces
   434         for (int i = 0; i < interfaces.length; i++) {
   418      */
   435             /*
   419     private static final Object key0 = new Object();
   436              * Verify that the class loader resolves the name of this
   420 
   437              * interface to the same Class object.
   421     /*
   438              */
   422      * Key1 and Key2 are optimized for the common use of dynamic proxies
   439             String interfaceName = interfaces[i].getName();
   423      * that implement 1 or 2 interfaces.
   440             Class<?> interfaceClass = null;
   424      */
   441             try {
   425 
   442                 interfaceClass = Class.forName(interfaceName, false, loader);
   426     /*
   443             } catch (ClassNotFoundException e) {
   427      * a key used for proxy class with 1 implemented interface
   444             }
   428      */
   445             if (interfaceClass != interfaces[i]) {
   429     private static final class Key1 extends WeakReference<Class<?>> {
   446                 throw new IllegalArgumentException(
   430         private final int hash;
   447                     interfaces[i] + " is not visible from class loader");
   431 
   448             }
   432         Key1(Class<?> intf) {
   449 
   433             super(intf);
   450             /*
   434             this.hash = intf.hashCode();
   451              * Verify that the Class object actually represents an
   435         }
   452              * interface.
   436 
   453              */
   437         @Override
   454             if (!interfaceClass.isInterface()) {
   438         public int hashCode() {
   455                 throw new IllegalArgumentException(
   439             return hash;
   456                     interfaceClass.getName() + " is not an interface");
   440         }
   457             }
   441 
   458 
   442         @Override
   459             /*
   443         public boolean equals(Object obj) {
   460              * Verify that this interface is not a duplicate.
   444             Class<?> intf;
   461              */
   445             return this == obj ||
   462             if (interfaceSet.contains(interfaceClass)) {
   446                    obj != null &&
   463                 throw new IllegalArgumentException(
   447                    obj.getClass() == Key1.class &&
   464                     "repeated interface: " + interfaceClass.getName());
   448                    (intf = get()) != null &&
   465             }
   449                    intf == ((Key1) obj).get();
   466             interfaceSet.add(interfaceClass);
   450         }
   467 
   451     }
   468             interfaceNames[i] = interfaceName;
   452 
   469         }
   453     /*
   470 
   454      * a key used for proxy class with 2 implemented interfaces
   471         /*
   455      */
   472          * Using string representations of the proxy interfaces as
   456     private static final class Key2 extends WeakReference<Class<?>> {
   473          * keys in the proxy class cache (instead of their Class
   457         private final int hash;
   474          * objects) is sufficient because we require the proxy
   458         private final WeakReference<Class<?>> ref2;
   475          * interfaces to be resolvable by name through the supplied
   459 
   476          * class loader, and it has the advantage that using a string
   460         Key2(Class<?> intf1, Class<?> intf2) {
   477          * representation of a class makes for an implicit weak
   461             super(intf1);
   478          * reference to the class.
   462             hash = 31 * intf1.hashCode() + intf2.hashCode();
   479          */
   463             ref2 = new WeakReference<Class<?>>(intf2);
   480         List<String> key = Arrays.asList(interfaceNames);
   464         }
   481 
   465 
   482         /*
   466         @Override
   483          * Find or create the proxy class cache for the class loader.
   467         public int hashCode() {
   484          */
   468             return hash;
   485         Map<List<String>, Object> cache;
   469         }
   486         synchronized (loaderToCache) {
   470 
   487             cache = loaderToCache.get(loader);
   471         @Override
   488             if (cache == null) {
   472         public boolean equals(Object obj) {
   489                 cache = new HashMap<>();
   473             Class<?> intf1, intf2;
   490                 loaderToCache.put(loader, cache);
   474             return this == obj ||
   491             }
   475                    obj != null &&
   492             /*
   476                    obj.getClass() == Key2.class &&
   493              * This mapping will remain valid for the duration of this
   477                    (intf1 = get()) != null &&
   494              * method, without further synchronization, because the mapping
   478                    intf1 == ((Key2) obj).get() &&
   495              * will only be removed if the class loader becomes unreachable.
   479                    (intf2 = ref2.get()) != null &&
   496              */
   480                    intf2 == ((Key2) obj).ref2.get();
   497         }
   481         }
   498 
   482     }
   499         /*
   483 
   500          * Look up the list of interfaces in the proxy class cache using
   484     /*
   501          * the key.  This lookup will result in one of three possible
   485      * a key used for proxy class with any number of implemented interfaces
   502          * kinds of values:
   486      * (used here for 3 or more only)
   503          *     null, if there is currently no proxy class for the list of
   487      */
   504          *         interfaces in the class loader,
   488     private static final class KeyX {
   505          *     the pendingGenerationMarker object, if a proxy class for the
   489         private final int hash;
   506          *         list of interfaces is currently being generated,
   490         private final WeakReference<Class<?>>[] refs;
   507          *     or a weak reference to a Class object, if a proxy class for
   491 
   508          *         the list of interfaces has already been generated.
   492         KeyX(Class<?>[] interfaces) {
   509          */
   493             hash = Arrays.hashCode(interfaces);
   510         synchronized (cache) {
   494             refs = new WeakReference[interfaces.length];
   511             /*
   495             for (int i = 0; i < interfaces.length; i++) {
   512              * Note that we need not worry about reaping the cache for
   496                 refs[i] = new WeakReference<>(interfaces[i]);
   513              * entries with cleared weak references because if a proxy class
   497             }
   514              * has been garbage collected, its class loader will have been
   498         }
   515              * garbage collected as well, so the entire cache will be reaped
   499 
   516              * from the loaderToCache map.
   500         @Override
   517              */
   501         public int hashCode() {
   518             do {
   502             return hash;
   519                 Object value = cache.get(key);
   503         }
   520                 if (value instanceof Reference) {
   504 
   521                     proxyClass = (Class<?>) ((Reference) value).get();
   505         @Override
       
   506         public boolean equals(Object obj) {
       
   507             return this == obj ||
       
   508                    obj != null &&
       
   509                    obj.getClass() == KeyX.class &&
       
   510                    equals(refs, ((KeyX) obj).refs);
       
   511         }
       
   512 
       
   513         private static boolean equals(WeakReference<Class<?>>[] refs1,
       
   514                                       WeakReference<Class<?>>[] refs2) {
       
   515             if (refs1.length != refs2.length) {
       
   516                 return false;
       
   517             }
       
   518             for (int i = 0; i < refs1.length; i++) {
       
   519                 Class<?> intf = refs1[i].get();
       
   520                 if (intf == null || intf != refs2[i].get()) {
       
   521                     return false;
   522                 }
   522                 }
   523                 if (proxyClass != null) {
   523             }
   524                     // proxy class already generated: return it
   524             return true;
   525                     return proxyClass;
   525         }
   526                 } else if (value == pendingGenerationMarker) {
   526     }
   527                     // proxy class being generated: wait for it
   527 
   528                     try {
   528     /**
   529                         cache.wait();
   529      * A function that maps an array of interfaces to an optimal key where
   530                     } catch (InterruptedException e) {
   530      * Class objects representing interfaces are weakly referenced.
   531                         /*
   531      */
   532                          * The class generation that we are waiting for should
   532     private static final class KeyFactory
   533                          * take a small, bounded time, so we can safely ignore
   533         implements BiFunction<ClassLoader, Class<?>[], Object>
   534                          * thread interrupts here.
   534     {
   535                          */
   535         @Override
   536                     }
   536         public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
   537                     continue;
   537             switch (interfaces.length) {
   538                 } else {
   538                 case 1: return new Key1(interfaces[0]); // the most frequent
   539                     /*
   539                 case 2: return new Key2(interfaces[0], interfaces[1]);
   540                      * No proxy class for this list of interfaces has been
   540                 case 0: return key0;
   541                      * generated or is being generated, so we will go and
   541                 default: return new KeyX(interfaces);
   542                      * generate it now.  Mark it as pending generation.
   542             }
   543                      */
   543         }
   544                     cache.put(key, pendingGenerationMarker);
   544     }
   545                     break;
   545 
       
   546     /**
       
   547      * A factory function that generates, defines and returns the proxy class given
       
   548      * the ClassLoader and array of interfaces.
       
   549      */
       
   550     private static final class ProxyClassFactory
       
   551         implements BiFunction<ClassLoader, Class<?>[], Class<?>>
       
   552     {
       
   553         // prefix for all proxy class names
       
   554         private static final String proxyClassNamePrefix = "$Proxy";
       
   555 
       
   556         // next number to use for generation of unique proxy class names
       
   557         private static final AtomicLong nextUniqueNumber = new AtomicLong();
       
   558 
       
   559         @Override
       
   560         public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
       
   561 
       
   562             Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
       
   563             for (Class<?> intf : interfaces) {
       
   564                 /*
       
   565                  * Verify that the class loader resolves the name of this
       
   566                  * interface to the same Class object.
       
   567                  */
       
   568                 Class<?> interfaceClass = null;
       
   569                 try {
       
   570                     interfaceClass = Class.forName(intf.getName(), false, loader);
       
   571                 } catch (ClassNotFoundException e) {
   546                 }
   572                 }
   547             } while (true);
   573                 if (interfaceClass != intf) {
   548         }
   574                     throw new IllegalArgumentException(
   549 
   575                         intf + " is not visible from class loader");
   550         try {
   576                 }
       
   577                 /*
       
   578                  * Verify that the Class object actually represents an
       
   579                  * interface.
       
   580                  */
       
   581                 if (!interfaceClass.isInterface()) {
       
   582                     throw new IllegalArgumentException(
       
   583                         interfaceClass.getName() + " is not an interface");
       
   584                 }
       
   585                 /*
       
   586                  * Verify that this interface is not a duplicate.
       
   587                  */
       
   588                 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
       
   589                     throw new IllegalArgumentException(
       
   590                         "repeated interface: " + interfaceClass.getName());
       
   591                 }
       
   592             }
       
   593 
   551             String proxyPkg = null;     // package to define proxy class in
   594             String proxyPkg = null;     // package to define proxy class in
   552             int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
   595             int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
   553 
   596 
   554             /*
   597             /*
   555              * Record the package of a non-public proxy interface so that the
   598              * Record the package of a non-public proxy interface so that the
   556              * proxy class will be defined in the same package.  Verify that
   599              * proxy class will be defined in the same package.  Verify that
   557              * all non-public proxy interfaces are in the same package.
   600              * all non-public proxy interfaces are in the same package.
   558              */
   601              */
   559             for (int i = 0; i < interfaces.length; i++) {
   602             for (Class<?> intf : interfaces) {
   560                 int flags = interfaces[i].getModifiers();
   603                 int flags = intf.getModifiers();
   561                 if (!Modifier.isPublic(flags)) {
   604                 if (!Modifier.isPublic(flags)) {
   562                     accessFlags = Modifier.FINAL;
   605                     accessFlags = Modifier.FINAL;
   563                     String name = interfaces[i].getName();
   606                     String name = intf.getName();
   564                     int n = name.lastIndexOf('.');
   607                     int n = name.lastIndexOf('.');
   565                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
   608                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
   566                     if (proxyPkg == null) {
   609                     if (proxyPkg == null) {
   567                         proxyPkg = pkg;
   610                         proxyPkg = pkg;
   568                     } else if (!pkg.equals(proxyPkg)) {
   611                     } else if (!pkg.equals(proxyPkg)) {
   575             if (proxyPkg == null) {
   618             if (proxyPkg == null) {
   576                 // if no non-public proxy interfaces, use com.sun.proxy package
   619                 // if no non-public proxy interfaces, use com.sun.proxy package
   577                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
   620                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
   578             }
   621             }
   579 
   622 
   580             {
   623             /*
       
   624              * Choose a name for the proxy class to generate.
       
   625              */
       
   626             long num = nextUniqueNumber.getAndIncrement();
       
   627             String proxyName = proxyPkg + proxyClassNamePrefix + num;
       
   628 
       
   629             /*
       
   630              * Generate the specified proxy class.
       
   631              */
       
   632             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
       
   633                 proxyName, interfaces, accessFlags);
       
   634             try {
       
   635                 return defineClass0(loader, proxyName,
       
   636                                     proxyClassFile, 0, proxyClassFile.length);
       
   637             } catch (ClassFormatError e) {
   581                 /*
   638                 /*
   582                  * Choose a name for the proxy class to generate.
   639                  * A ClassFormatError here means that (barring bugs in the
       
   640                  * proxy class generation code) there was some other
       
   641                  * invalid aspect of the arguments supplied to the proxy
       
   642                  * class creation (such as virtual machine limitations
       
   643                  * exceeded).
   583                  */
   644                  */
   584                 long num;
   645                 throw new IllegalArgumentException(e.toString());
   585                 synchronized (nextUniqueNumberLock) {
   646             }
   586                     num = nextUniqueNumber++;
   647         }
   587                 }
       
   588                 String proxyName = proxyPkg + proxyClassNamePrefix + num;
       
   589                 /*
       
   590                  * Verify that the class loader hasn't already
       
   591                  * defined a class with the chosen name.
       
   592                  */
       
   593 
       
   594                 /*
       
   595                  * Generate the specified proxy class.
       
   596                  */
       
   597                 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
       
   598                     proxyName, interfaces, accessFlags);
       
   599                 try {
       
   600                     proxyClass = defineClass0(loader, proxyName,
       
   601                         proxyClassFile, 0, proxyClassFile.length);
       
   602                 } catch (ClassFormatError e) {
       
   603                     /*
       
   604                      * A ClassFormatError here means that (barring bugs in the
       
   605                      * proxy class generation code) there was some other
       
   606                      * invalid aspect of the arguments supplied to the proxy
       
   607                      * class creation (such as virtual machine limitations
       
   608                      * exceeded).
       
   609                      */
       
   610                     throw new IllegalArgumentException(e.toString());
       
   611                 }
       
   612             }
       
   613             // add to set of all generated proxy classes, for isProxyClass
       
   614             proxyClasses.put(proxyClass, null);
       
   615 
       
   616         } finally {
       
   617             /*
       
   618              * We must clean up the "pending generation" state of the proxy
       
   619              * class cache entry somehow.  If a proxy class was successfully
       
   620              * generated, store it in the cache (with a weak reference);
       
   621              * otherwise, remove the reserved entry.  In all cases, notify
       
   622              * all waiters on reserved entries in this cache.
       
   623              */
       
   624             synchronized (cache) {
       
   625                 if (proxyClass != null) {
       
   626                     cache.put(key, new WeakReference<Class<?>>(proxyClass));
       
   627                 } else {
       
   628                     cache.remove(key);
       
   629                 }
       
   630                 cache.notifyAll();
       
   631             }
       
   632         }
       
   633         return proxyClass;
       
   634     }
   648     }
   635 
   649 
   636     /**
   650     /**
   637      * Returns an instance of a proxy class for the specified interfaces
   651      * Returns an instance of a proxy class for the specified interfaces
   638      * that dispatches method invocations to the specified invocation
   652      * that dispatches method invocations to the specified invocation
   755                 sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
   769                 sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
   756             }
   770             }
   757         }
   771         }
   758     }
   772     }
   759 
   773 
   760     private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
       
   761         try {
       
   762             return cons.newInstance(new Object[] {h} );
       
   763         } catch (IllegalAccessException | InstantiationException e) {
       
   764             throw new InternalError(e.toString(), e);
       
   765         } catch (InvocationTargetException e) {
       
   766             Throwable t = e.getCause();
       
   767             if (t instanceof RuntimeException) {
       
   768                 throw (RuntimeException) t;
       
   769             } else {
       
   770                 throw new InternalError(t.toString(), t);
       
   771             }
       
   772         }
       
   773     }
       
   774 
       
   775     /**
   774     /**
   776      * Returns true if and only if the specified class was dynamically
   775      * Returns true if and only if the specified class was dynamically
   777      * generated to be a proxy class using the {@code getProxyClass}
   776      * generated to be a proxy class using the {@code getProxyClass}
   778      * method or the {@code newProxyInstance} method.
   777      * method or the {@code newProxyInstance} method.
   779      *
   778      *
   785      * @return  {@code true} if the class is a proxy class and
   784      * @return  {@code true} if the class is a proxy class and
   786      *          {@code false} otherwise
   785      *          {@code false} otherwise
   787      * @throws  NullPointerException if {@code cl} is {@code null}
   786      * @throws  NullPointerException if {@code cl} is {@code null}
   788      */
   787      */
   789     public static boolean isProxyClass(Class<?> cl) {
   788     public static boolean isProxyClass(Class<?> cl) {
   790         if (cl == null) {
   789         return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
   791             throw new NullPointerException();
       
   792         }
       
   793 
       
   794         return proxyClasses.containsKey(cl);
       
   795     }
   790     }
   796 
   791 
   797     /**
   792     /**
   798      * Returns the invocation handler for the specified proxy instance.
   793      * Returns the invocation handler for the specified proxy instance.
   799      *
   794      *