< prev index next >

src/java.base/share/classes/java/lang/reflect/Proxy.java

Print this page

  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.reflect;
  27 
  28 import java.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles;
  30 import java.lang.invoke.MethodType;
  31 import java.lang.invoke.WrongMethodTypeException;
  32 import java.lang.module.ModuleDescriptor;
  33 import java.util.ArrayDeque;

  34 import java.util.Arrays;
  35 import java.util.Collections;
  36 import java.util.Deque;
  37 import java.util.HashMap;
  38 import java.util.HashSet;
  39 import java.util.IdentityHashMap;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.Objects;
  43 import java.util.Set;
  44 import java.util.concurrent.ConcurrentHashMap;
  45 import java.util.concurrent.atomic.AtomicInteger;
  46 import java.util.concurrent.atomic.AtomicLong;
  47 import java.util.function.BooleanSupplier;
  48 
  49 import jdk.internal.access.JavaLangAccess;
  50 import jdk.internal.access.SharedSecrets;
  51 import jdk.internal.module.Modules;
  52 import jdk.internal.misc.VM;

  53 import jdk.internal.loader.ClassLoaderValue;
  54 import jdk.internal.vm.annotation.Stable;
  55 
  56 import static java.lang.invoke.MethodType.methodType;
  57 import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
  58 
  59 /**
  60  *
  61  * {@code Proxy} provides static methods for creating objects that act like instances
  62  * of interfaces but allow for customized method invocation.
  63  * To create a proxy instance for some interface {@code Foo}:
  64  * <pre>{@code
  65  *     InvocationHandler handler = new MyInvocationHandler(...);
  66  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  67  *                                          new Class<?>[] { Foo.class },
  68  *                                          handler);
  69  * }</pre>
  70  *
  71  * <p>
  72  * A <em>proxy class</em> is a class created at runtime that implements a specified

 383                                                       Class<?>... interfaces)
 384     {
 385         // optimization for single interface
 386         if (interfaces.length == 1) {
 387             Class<?> intf = interfaces[0];
 388             return proxyCache.sub(intf).computeIfAbsent(
 389                 loader,
 390                 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
 391             );
 392         } else {
 393             // interfaces cloned
 394             final Class<?>[] intfsArray = interfaces.clone();
 395             final List<Class<?>> intfs = Arrays.asList(intfsArray);
 396             return proxyCache.sub(intfs).computeIfAbsent(
 397                 loader,
 398                 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
 399             );
 400         }
 401     }
 402 







 403     /**
 404      * Builder for a proxy class.
 405      *
 406      * If the module is not specified in this ProxyBuilder constructor,
 407      * it will map from the given loader and interfaces to the module
 408      * in which the proxy class will be defined.
 409      */
 410     private static final class ProxyBuilder {
 411         private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 412 













 413         // prefix for all proxy class names
 414         private static final String proxyClassNamePrefix = "$Proxy";
 415 
 416         // next number to use for generation of unique proxy class names
 417         private static final AtomicLong nextUniqueNumber = new AtomicLong();
 418 
 419         // a reverse cache of defined proxy classes
 420         private static final ClassLoaderValue<Boolean> reverseProxyCache =
 421             new ClassLoaderValue<>();
 422 
 423         private record ProxyClassContext(Module module, String packageName, int accessFlags) {
 424             private ProxyClassContext {
 425                 if (module.isNamed()) {
 426                     if (packageName.isEmpty()) {
 427                         // Per JLS 7.4.2, unnamed package can only exist in unnamed modules.
 428                         // This means a package-private superinterface exist in the unnamed
 429                         // package of a named module.
 430                         throw new InternalError("Unnamed package cannot be added to " + module);
 431                     }
 432 
 433                     if (!module.getDescriptor().packages().contains(packageName)) {
 434                         throw new InternalError(packageName + " not exist in " + module.getName());
 435                     }
 436 
 437                     if (!module.isOpen(packageName, Proxy.class.getModule())) {
 438                         // Required for default method invocation
 439                         throw new InternalError(packageName + " not open to " + Proxy.class.getModule());
 440                     }
 441                 } else {
 442                     if (Modifier.isPublic(accessFlags)) {
 443                         // All proxy superinterfaces are public, must be in named dynamic module
 444                         throw new InternalError("public proxy in unnamed module: " + module);
 445                     }
 446                 }
 447 
 448                 if ((accessFlags & ~Modifier.PUBLIC) != 0) {
 449                     throw new InternalError("proxy access flags must be Modifier.PUBLIC or 0");
 450                 }
 451             }
 452         }
 453 
 454         private static Class<?> defineProxyClass(ProxyClassContext context, List<Class<?>> interfaces) {
 455             /*
 456              * Choose a name for the proxy class to generate.
 457              */














 458             long num = nextUniqueNumber.getAndIncrement();
 459             String proxyName = context.packageName().isEmpty()
 460                                     ? proxyClassNamePrefix + num
 461                                     : context.packageName() + "." + proxyClassNamePrefix + num;
 462 
 463             ClassLoader loader = context.module().getClassLoader();
 464             trace(proxyName, context.module(), loader, interfaces);
 465 




 466             /*
 467              * Generate the specified proxy class.
 468              */
 469             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces,
 470                                                                       context.accessFlags() | Modifier.FINAL);
 471             try {
 472                 Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
 473                                               null, "__dynamic_proxy__");
 474                 reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
 475                 return pc;
 476             } catch (ClassFormatError e) {
 477                 /*
 478                  * A ClassFormatError here means that (barring bugs in the
 479                  * proxy class generation code) there was some other
 480                  * invalid aspect of the arguments supplied to the proxy
 481                  * class creation (such as virtual machine limitations
 482                  * exceeded).
 483                  */
 484                 throw new IllegalArgumentException(e.toString());
 485             }
 486         }
 487 

















 488         /**
 489          * Test if given class is a class defined by
 490          * {@link #defineProxyClass(ProxyClassContext, List)}
 491          */
 492         static boolean isProxyClass(Class<?> c) {
 493             return Objects.equals(reverseProxyCache.sub(c).get(c.getClassLoader()),
 494                                   Boolean.TRUE);
 495         }
 496 
 497         private static boolean isExportedType(Class<?> c) {
 498             String pn = c.getPackageName();
 499             return Modifier.isPublic(c.getModifiers()) && c.getModule().isExported(pn);
 500         }
 501 
 502         private static boolean isPackagePrivateType(Class<?> c) {
 503             return !Modifier.isPublic(c.getModifiers());
 504         }
 505 
 506         private static String toDetails(Class<?> c) {
 507             String access = "unknown";

 731 
 732                     targetModule = m;
 733                     targetPackageName = e.getKey().getPackageName();
 734                 }
 735 
 736                 // validate if the target module can access all other interfaces
 737                 for (Class<?> intf : interfaces) {
 738                     Module m = intf.getModule();
 739                     if (m == targetModule) continue;
 740 
 741                     if (!targetModule.canRead(m) || !m.isExported(intf.getPackageName(), targetModule)) {
 742                         throw new IllegalArgumentException(targetModule + " can't access " + intf.getName());
 743                     }
 744                 }
 745 
 746                 // opens the package of the non-public proxy class for java.base to access
 747                 if (targetModule.isNamed()) {
 748                     Modules.addOpens(targetModule, targetPackageName, Proxy.class.getModule());
 749                 }
 750                 // return the module of the package-private interface
 751                 return new ProxyClassContext(targetModule, targetPackageName, 0);
 752             }
 753 
 754             // All proxy interfaces are public.  So maps to a dynamic proxy module
 755             // and add reads edge and qualified exports, if necessary
 756             Module targetModule = getDynamicModule(loader);
 757 
 758             // set up proxy class access to proxy interfaces and types
 759             // referenced in the method signature
 760             Set<Class<?>> types = new HashSet<>(interfaces);
 761             types.addAll(refTypes);
 762             for (Class<?> c : types) {
 763                 ensureAccess(targetModule, c);
 764             }
 765 
 766             var pkgName = nonExported ? PROXY_PACKAGE_PREFIX + '.' + targetModule.getName()
 767                                       : targetModule.getName();
 768             return new ProxyClassContext(targetModule, pkgName, Modifier.PUBLIC);
 769         }
 770 
 771         /*
 772          * Ensure the given module can access the given class.
 773          */
 774         private static void ensureAccess(Module target, Class<?> c) {
 775             Module m = c.getModule();
 776             if (target == m) return;
 777 
 778             // add read edge and qualified export for the target module to access
 779             if (!target.canRead(m)) {
 780                 Modules.addReads(target, m);
 781             }
 782             String pn = c.getPackageName();
 783             if (!m.isExported(pn, target)) {
 784                 Modules.addExports(m, pn, target);
 785             }
 786         }
 787 
 788         /*

 805             while (e.isArray()) {
 806                 e = e.getComponentType();
 807             }
 808             return e;
 809         }
 810 
 811         private static final ClassLoaderValue<Module> dynProxyModules =
 812             new ClassLoaderValue<>();
 813         private static final AtomicInteger counter = new AtomicInteger();
 814 
 815         /*
 816          * Define a dynamic module with a package named $MODULE which
 817          * is unconditionally exported and another package named
 818          * com.sun.proxy.$MODULE which is encapsulated.
 819          *
 820          * Each class loader will have one dynamic module.
 821          */
 822         private static Module getDynamicModule(ClassLoader loader) {
 823             return dynProxyModules.computeIfAbsent(loader, (ld, clv) -> {
 824                 // create a dynamic module and setup module access
 825                 String mn = "jdk.proxy" + counter.incrementAndGet();

 826                 String pn = PROXY_PACKAGE_PREFIX + "." + mn;
 827                 ModuleDescriptor descriptor =
 828                         ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
 829                                         .packages(Set.of(pn, mn))
 830                                         .exports(mn)
 831                                         .build();
 832                 Module m = Modules.defineModule(ld, descriptor, null);
 833                 Modules.addReads(m, Proxy.class.getModule());
 834                 Modules.addExports(m, mn);
 835                 // java.base to create proxy instance and access its Lookup instance
 836                 Modules.addOpens(m, pn, Proxy.class.getModule());
 837                 Modules.addOpens(m, mn, Proxy.class.getModule());
 838                 return m;
 839             });
 840         }



















































































































































 841     }
 842 
 843     /**
 844      * Returns a proxy instance for the specified interfaces
 845      * that dispatches method invocations to the specified invocation
 846      * handler.
 847      * <p>
 848      * <a id="restrictions">{@code IllegalArgumentException} will be thrown
 849      * if any of the following restrictions is violated:</a>
 850      * <ul>
 851      * <li>All of {@code Class} objects in the given {@code interfaces} array
 852      * must represent {@linkplain Class#isHidden() non-hidden} and
 853      * {@linkplain Class#isSealed() non-sealed} interfaces,
 854      * not classes or primitive types.
 855      *
 856      * <li>No two elements in the {@code interfaces} array may
 857      * refer to identical {@code Class} objects.
 858      *
 859      * <li>All of the interface types must be visible by name through the
 860      * specified class loader. In other words, for class loader

  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.reflect;
  27 
  28 import java.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles;
  30 import java.lang.invoke.MethodType;
  31 import java.lang.invoke.WrongMethodTypeException;
  32 import java.lang.module.ModuleDescriptor;
  33 import java.util.ArrayDeque;
  34 import java.util.ArrayList;
  35 import java.util.Arrays;
  36 import java.util.Collections;
  37 import java.util.Deque;
  38 import java.util.HashMap;
  39 import java.util.HashSet;
  40 import java.util.IdentityHashMap;
  41 import java.util.List;
  42 import java.util.Map;
  43 import java.util.Objects;
  44 import java.util.Set;
  45 import java.util.concurrent.ConcurrentHashMap;
  46 import java.util.concurrent.atomic.AtomicInteger;
  47 import java.util.concurrent.atomic.AtomicLong;
  48 import java.util.function.BooleanSupplier;
  49 
  50 import jdk.internal.access.JavaLangAccess;
  51 import jdk.internal.access.SharedSecrets;
  52 import jdk.internal.module.Modules;
  53 import jdk.internal.misc.VM;
  54 import jdk.internal.misc.CDS;
  55 import jdk.internal.loader.ClassLoaderValue;
  56 import jdk.internal.vm.annotation.Stable;
  57 
  58 import static java.lang.invoke.MethodType.methodType;
  59 import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
  60 
  61 /**
  62  *
  63  * {@code Proxy} provides static methods for creating objects that act like instances
  64  * of interfaces but allow for customized method invocation.
  65  * To create a proxy instance for some interface {@code Foo}:
  66  * <pre>{@code
  67  *     InvocationHandler handler = new MyInvocationHandler(...);
  68  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  69  *                                          new Class<?>[] { Foo.class },
  70  *                                          handler);
  71  * }</pre>
  72  *
  73  * <p>
  74  * A <em>proxy class</em> is a class created at runtime that implements a specified

 385                                                       Class<?>... interfaces)
 386     {
 387         // optimization for single interface
 388         if (interfaces.length == 1) {
 389             Class<?> intf = interfaces[0];
 390             return proxyCache.sub(intf).computeIfAbsent(
 391                 loader,
 392                 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
 393             );
 394         } else {
 395             // interfaces cloned
 396             final Class<?>[] intfsArray = interfaces.clone();
 397             final List<Class<?>> intfs = Arrays.asList(intfsArray);
 398             return proxyCache.sub(intfs).computeIfAbsent(
 399                 loader,
 400                 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
 401             );
 402         }
 403     }
 404 
 405     /**
 406      * Called from VM native code during dump time.
 407      */
 408     private static void initCacheForCDS(ClassLoader platformLoader, ClassLoader appLoader) {
 409         ProxyBuilder.initCacheForCDS(platformLoader, appLoader);
 410     }
 411 
 412     /**
 413      * Builder for a proxy class.
 414      *
 415      * If the module is not specified in this ProxyBuilder constructor,
 416      * it will map from the given loader and interfaces to the module
 417      * in which the proxy class will be defined.
 418      */
 419     private static final class ProxyBuilder {
 420         private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 421 
 422         private static String makeProxyClassNamePrefix() {
 423             // Allow unique proxy names to be used across CDS dump time and app run time.
 424             if (CDS.isDumpingArchive()) {
 425                 if (CDS.isUsingArchive()) {
 426                     return "$Proxy0100"; // CDS dynamic dump
 427                 } else {
 428                     return "$Proxy0010"; // CDS static dump
 429                 }
 430             } else {
 431                 return "$Proxy";
 432             }
 433         }
 434 
 435         // prefix for all proxy class names
 436         private static final String proxyClassNamePrefix = makeProxyClassNamePrefix();
 437 
 438         // next number to use for generation of unique proxy class names
 439         private static final AtomicLong nextUniqueNumber = new AtomicLong();
 440 
 441         // a reverse cache of defined proxy classes
 442         private static final ClassLoaderValue<Boolean> reverseProxyCache =
 443             new ClassLoaderValue<>();
 444 
 445         private record ProxyClassContext(Module module, String packageName, int accessFlags, boolean isDynamicModule) {
 446             private ProxyClassContext {
 447                 if (module.isNamed()) {
 448                     if (packageName.isEmpty()) {
 449                         // Per JLS 7.4.2, unnamed package can only exist in unnamed modules.
 450                         // This means a package-private superinterface exist in the unnamed
 451                         // package of a named module.
 452                         throw new InternalError("Unnamed package cannot be added to " + module);
 453                     }
 454 
 455                     if (!module.getDescriptor().packages().contains(packageName)) {
 456                         throw new InternalError(packageName + " not exist in " + module.getName());
 457                     }
 458 
 459                     if (!module.isOpen(packageName, Proxy.class.getModule())) {
 460                         // Required for default method invocation
 461                         throw new InternalError(packageName + " not open to " + Proxy.class.getModule());
 462                     }
 463                 } else {
 464                     if (Modifier.isPublic(accessFlags)) {
 465                         // All proxy superinterfaces are public, must be in named dynamic module
 466                         throw new InternalError("public proxy in unnamed module: " + module);
 467                     }
 468                 }
 469 
 470                 if ((accessFlags & ~Modifier.PUBLIC) != 0) {
 471                     throw new InternalError("proxy access flags must be Modifier.PUBLIC or 0");
 472                 }
 473             }
 474         }
 475 
 476         private static Class<?> defineProxyClass(ProxyClassContext context, List<Class<?>> interfaces) {
 477             /*
 478              * Choose a name for the proxy class to generate.
 479              */
 480             String packagePrefix = context.packageName().isEmpty()
 481                                     ? proxyClassNamePrefix
 482                                     : context.packageName() + "." + proxyClassNamePrefix;
 483             ClassLoader loader = context.module().getClassLoader();
 484             int accessFlags = context.accessFlags() | Modifier.FINAL;
 485 
 486             if (archivedData != null) {
 487                 Class<?> pc = archivedData.getArchivedProxyClass(loader, packagePrefix, interfaces);
 488                 if (pc != null) {
 489                     reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
 490                     return pc;
 491                 }
 492             }
 493 
 494             long num = nextUniqueNumber.getAndIncrement();
 495             String proxyName = packagePrefix + num;


 496 

 497             trace(proxyName, context.module(), loader, interfaces);
 498 
 499             if (CDS.isLoggingDynamicProxies() && context.isDynamicModule()) {
 500                 CDS.logDynamicProxy(loader, proxyName, interfaces.toArray(new Class<?>[0]), accessFlags);
 501             }
 502 
 503             /*
 504              * Generate the specified proxy class.
 505              */
 506             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);

 507             try {
 508                 Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
 509                                               null, "__dynamic_proxy__");
 510                 reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
 511                 return pc;
 512             } catch (ClassFormatError e) {
 513                 /*
 514                  * A ClassFormatError here means that (barring bugs in the
 515                  * proxy class generation code) there was some other
 516                  * invalid aspect of the arguments supplied to the proxy
 517                  * class creation (such as virtual machine limitations
 518                  * exceeded).
 519                  */
 520                 throw new IllegalArgumentException(e.toString());
 521             }
 522         }
 523 
 524         /**
 525          * Called from VM native code to define a proxy class to be stored in archivedData.
 526          */
 527         private static Class<?> defineProxyClassForCDS(ClassLoader loader, String proxyName, Class<?>[] interfaces,
 528                                                        int accessFlags) {
 529             ArrayList<Class<?>> list = new ArrayList<>();
 530             for (Object o : interfaces) {
 531                 list.add((Class<?>)o);
 532             }
 533 
 534             ProxyBuilder builder = new ProxyBuilder(loader, list);
 535             Constructor<?> cons = builder.build();
 536             Class<?> proxyClass = cons.getDeclaringClass();
 537             archivedData.putArchivedProxyClass(loader, proxyName, list, proxyClass);
 538             return proxyClass;
 539         }
 540 
 541         /**
 542          * Test if given class is a class defined by
 543          * {@link #defineProxyClass(ProxyClassContext, List)}
 544          */
 545         static boolean isProxyClass(Class<?> c) {
 546             return Objects.equals(reverseProxyCache.sub(c).get(c.getClassLoader()),
 547                                   Boolean.TRUE);
 548         }
 549 
 550         private static boolean isExportedType(Class<?> c) {
 551             String pn = c.getPackageName();
 552             return Modifier.isPublic(c.getModifiers()) && c.getModule().isExported(pn);
 553         }
 554 
 555         private static boolean isPackagePrivateType(Class<?> c) {
 556             return !Modifier.isPublic(c.getModifiers());
 557         }
 558 
 559         private static String toDetails(Class<?> c) {
 560             String access = "unknown";

 784 
 785                     targetModule = m;
 786                     targetPackageName = e.getKey().getPackageName();
 787                 }
 788 
 789                 // validate if the target module can access all other interfaces
 790                 for (Class<?> intf : interfaces) {
 791                     Module m = intf.getModule();
 792                     if (m == targetModule) continue;
 793 
 794                     if (!targetModule.canRead(m) || !m.isExported(intf.getPackageName(), targetModule)) {
 795                         throw new IllegalArgumentException(targetModule + " can't access " + intf.getName());
 796                     }
 797                 }
 798 
 799                 // opens the package of the non-public proxy class for java.base to access
 800                 if (targetModule.isNamed()) {
 801                     Modules.addOpens(targetModule, targetPackageName, Proxy.class.getModule());
 802                 }
 803                 // return the module of the package-private interface
 804                 return new ProxyClassContext(targetModule, targetPackageName, 0, false);
 805             }
 806 
 807             // All proxy interfaces are public.  So maps to a dynamic proxy module
 808             // and add reads edge and qualified exports, if necessary
 809             Module targetModule = getDynamicModule(loader);
 810 
 811             // set up proxy class access to proxy interfaces and types
 812             // referenced in the method signature
 813             Set<Class<?>> types = new HashSet<>(interfaces);
 814             types.addAll(refTypes);
 815             for (Class<?> c : types) {
 816                 ensureAccess(targetModule, c);
 817             }
 818 
 819             var pkgName = nonExported ? PROXY_PACKAGE_PREFIX + '.' + targetModule.getName()
 820                                       : targetModule.getName();
 821             return new ProxyClassContext(targetModule, pkgName, Modifier.PUBLIC, true);
 822         }
 823 
 824         /*
 825          * Ensure the given module can access the given class.
 826          */
 827         private static void ensureAccess(Module target, Class<?> c) {
 828             Module m = c.getModule();
 829             if (target == m) return;
 830 
 831             // add read edge and qualified export for the target module to access
 832             if (!target.canRead(m)) {
 833                 Modules.addReads(target, m);
 834             }
 835             String pn = c.getPackageName();
 836             if (!m.isExported(pn, target)) {
 837                 Modules.addExports(m, pn, target);
 838             }
 839         }
 840 
 841         /*

 858             while (e.isArray()) {
 859                 e = e.getComponentType();
 860             }
 861             return e;
 862         }
 863 
 864         private static final ClassLoaderValue<Module> dynProxyModules =
 865             new ClassLoaderValue<>();
 866         private static final AtomicInteger counter = new AtomicInteger();
 867 
 868         /*
 869          * Define a dynamic module with a package named $MODULE which
 870          * is unconditionally exported and another package named
 871          * com.sun.proxy.$MODULE which is encapsulated.
 872          *
 873          * Each class loader will have one dynamic module.
 874          */
 875         private static Module getDynamicModule(ClassLoader loader) {
 876             return dynProxyModules.computeIfAbsent(loader, (ld, clv) -> {
 877                 // create a dynamic module and setup module access
 878                 int num = counter.incrementAndGet();
 879                 String mn = "jdk.proxy" + num;
 880                 String pn = PROXY_PACKAGE_PREFIX + "." + mn;
 881                 ModuleDescriptor descriptor =
 882                         ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
 883                                         .packages(Set.of(pn, mn))
 884                                         .exports(mn)
 885                                         .build();
 886                 Module m = Modules.defineModule(ld, descriptor, null);
 887                 openDynamicModule(m);
 888 
 889                 if (CDS.isDumpingHeap() && archivedData != null) {
 890                     archivedData.recordModule(loader, m, num);
 891                 }
 892                 return m;
 893             });
 894         }
 895 
 896         private static void openDynamicModule(Module m) {
 897             String mn = m.getName();
 898             String pn = PROXY_PACKAGE_PREFIX + "." + mn;
 899             Modules.addReads(m, Proxy.class.getModule());
 900             Modules.addExports(m, mn);
 901             // java.base to create proxy instance and access its Lookup instance
 902             Modules.addOpens(m, pn, Proxy.class.getModule());
 903             Modules.addOpens(m, mn, Proxy.class.getModule());
 904         }
 905 
 906         static class ArchivedData {
 907             static class InterfacesKey {
 908                 Class<?>[] intfsArray;
 909                 InterfacesKey(List<Class<?>> intfs) {
 910                     intfsArray = new Class<?>[intfs.size()];
 911                     for (int i = 0; i < intfs.size(); i++) {
 912                         intfsArray[i] = intfs.get(i);
 913                     }
 914                 }
 915                 @Override
 916                 public int hashCode() {
 917                     return Arrays.hashCode(intfsArray);
 918                 }
 919                 @Override
 920                 public boolean equals(Object other) {
 921                     if (other instanceof InterfacesKey) {
 922                         InterfacesKey o = (InterfacesKey)other;
 923                         int len = intfsArray.length;
 924                         if (len != o.intfsArray.length) {
 925                             return false;
 926                         }
 927                         Class<?>[] oa = o.intfsArray;
 928                         for (int i = 0; i < len; i++) {
 929                             if (intfsArray[i] != oa[i]) {
 930                                 return false;
 931                             }
 932                         }
 933                         return true;
 934                     } else {
 935                         return false;
 936                     }
 937                 }
 938             }
 939 
 940             ClassLoader platformLoader;
 941             ClassLoader appLoader;
 942             HashMap<InterfacesKey,Class<?>> bootCache = new HashMap<>();
 943             HashMap<InterfacesKey,Class<?>> platformCache = new HashMap<>();
 944             HashMap<InterfacesKey,Class<?>> appCache = new HashMap<>();
 945 
 946             Module bootModule;
 947             Module platformModule;
 948             Module appModule;
 949             int maxNum;
 950 
 951             ArchivedData(ClassLoader plat, ClassLoader app) {
 952                 platformLoader = plat;
 953                 appLoader = app;
 954             }
 955 
 956             HashMap<InterfacesKey,Class<?>> cacheForLoader(ClassLoader loader) {
 957                 if (loader == null) {
 958                     return bootCache;
 959                 } else if (loader == platformLoader) {
 960                     return platformCache;
 961                 } else if (loader == appLoader) {
 962                     return appCache;
 963                 } else {
 964                     return null;
 965                 }
 966             }
 967 
 968             void recordModule(ClassLoader loader, Module m, int num) {
 969                 if (loader == null) {
 970                     bootModule = m;
 971                 } else if (loader == platformLoader) {
 972                     platformModule = m;
 973                 } else if (loader == appLoader) {
 974                     appModule = m;
 975                 } else {
 976                     throw new UnsupportedOperationException("Class loader " + loader + " is not supported");
 977                 }
 978                 if (maxNum < num) {
 979                     maxNum = num;
 980                 }
 981             }
 982 
 983             void restore() {
 984                 // The info for addReads/addExports/addOpens are maintained solely inside the VM.
 985                 // CDS currently doesn't properly archive such info for the dynamically generated modules,
 986                 // so we have to recreate them at runtime.
 987                 //
 988                 // TODO --  consider improving CDS to archive the above info, so we can avoid calling openDynamicModule()
 989                 if (bootModule != null) {
 990                     Module last = dynProxyModules.putIfAbsent(null, bootModule);
 991                     assert last == null;
 992                     openDynamicModule(bootModule);
 993                 }
 994                 if (platformModule != null) {
 995                     Module last = dynProxyModules.putIfAbsent(platformLoader, platformModule);
 996                     assert last == null;
 997                     openDynamicModule(platformModule);
 998                 }
 999                 if (appModule != null) {
1000                     Module last = dynProxyModules.putIfAbsent(appLoader, appModule);
1001                     assert last == null;
1002                     openDynamicModule(appModule);
1003                 }
1004 
1005                 while (maxNum > counter.get()) {
1006                     counter.incrementAndGet();
1007                 }
1008             }
1009 
1010 
1011             Class<?> getArchivedProxyClass(ClassLoader loader, String proxyPrefix, List<Class<?>> interfaces) {
1012                 HashMap<InterfacesKey,Class<?>> cache = cacheForLoader(loader);
1013                 if (cache != null && cache.size() > 0) {
1014                     InterfacesKey key = new InterfacesKey(interfaces);
1015                     return cache.get(key);
1016                 } else {
1017                     return null;
1018                 }
1019             }
1020 
1021             void putArchivedProxyClass(ClassLoader loader, String proxyName, List<Class<?>> interfaces, Class<?> cls) {
1022                 HashMap<InterfacesKey,Class<?>> cache = cacheForLoader(loader);
1023                 if (cache != null) {
1024                     InterfacesKey key = new InterfacesKey(interfaces);
1025                     cache.put(key, cls);
1026                 }
1027             }
1028         }
1029 
1030         static ArchivedData archivedData;
1031 
1032         static {
1033             CDS.initializeFromArchive(ProxyBuilder.class);
1034             if (archivedData != null) {
1035                 archivedData.restore();
1036             }
1037         }
1038 
1039         private static void initCacheForCDS(ClassLoader platformLoader, ClassLoader appLoader) {
1040             archivedData = new ArchivedData(platformLoader, appLoader);
1041         }
1042     }
1043 
1044     /**
1045      * Returns a proxy instance for the specified interfaces
1046      * that dispatches method invocations to the specified invocation
1047      * handler.
1048      * <p>
1049      * <a id="restrictions">{@code IllegalArgumentException} will be thrown
1050      * if any of the following restrictions is violated:</a>
1051      * <ul>
1052      * <li>All of {@code Class} objects in the given {@code interfaces} array
1053      * must represent {@linkplain Class#isHidden() non-hidden} and
1054      * {@linkplain Class#isSealed() non-sealed} interfaces,
1055      * not classes or primitive types.
1056      *
1057      * <li>No two elements in the {@code interfaces} array may
1058      * refer to identical {@code Class} objects.
1059      *
1060      * <li>All of the interface types must be visible by name through the
1061      * specified class loader. In other words, for class loader
< prev index next >