< 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 import sun.reflect.misc.ReflectUtil;
  56 
  57 import static java.lang.invoke.MethodType.methodType;
  58 import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
  59 
  60 /**
  61  *
  62  * {@code Proxy} provides static methods for creating objects that act like instances
  63  * of interfaces but allow for customized method invocation.
  64  * To create a proxy instance for some interface {@code Foo}:
  65  * <pre>{@code
  66  *     InvocationHandler handler = new MyInvocationHandler(...);
  67  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  68  *                                          new Class<?>[] { Foo.class },
  69  *                                          handler);
  70  * }</pre>
  71  *
  72  * <p>

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







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













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














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




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

















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

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

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

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



















































































































































 842     }
 843 
 844     /**
 845      * Returns a proxy instance for the specified interfaces
 846      * that dispatches method invocations to the specified invocation
 847      * handler.
 848      * <p>
 849      * <a id="restrictions">{@code IllegalArgumentException} will be thrown
 850      * if any of the following restrictions is violated:</a>
 851      * <ul>
 852      * <li>All of {@code Class} objects in the given {@code interfaces} array
 853      * must represent {@linkplain Class#isHidden() non-hidden} and
 854      * {@linkplain Class#isSealed() non-sealed} interfaces,
 855      * not classes or primitive types.
 856      *
 857      * <li>No two elements in the {@code interfaces} array may
 858      * refer to identical {@code Class} objects.
 859      *
 860      * <li>All of the interface types must be visible by name through the
 861      * 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 import sun.reflect.misc.ReflectUtil;
  58 
  59 import static java.lang.invoke.MethodType.methodType;
  60 import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
  61 
  62 /**
  63  *
  64  * {@code Proxy} provides static methods for creating objects that act like instances
  65  * of interfaces but allow for customized method invocation.
  66  * To create a proxy instance for some interface {@code Foo}:
  67  * <pre>{@code
  68  *     InvocationHandler handler = new MyInvocationHandler(...);
  69  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  70  *                                          new Class<?>[] { Foo.class },
  71  *                                          handler);
  72  * }</pre>
  73  *
  74  * <p>

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


 497 

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

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

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

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