< prev index next >

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

Print this page

  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.security.AccessController;
  34 import java.security.PrivilegedAction;
  35 import java.util.ArrayDeque;

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

  55 import jdk.internal.reflect.CallerSensitive;
  56 import jdk.internal.reflect.Reflection;
  57 import jdk.internal.loader.ClassLoaderValue;
  58 import jdk.internal.vm.annotation.Stable;
  59 import sun.reflect.misc.ReflectUtil;
  60 import sun.security.action.GetPropertyAction;
  61 import sun.security.util.SecurityConstants;
  62 
  63 import static java.lang.invoke.MethodType.methodType;
  64 import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
  65 
  66 /**
  67  *
  68  * {@code Proxy} provides static methods for creating objects that act like instances
  69  * of interfaces but allow for customized method invocation.
  70  * To create a proxy instance for some interface {@code Foo}:
  71  * <pre>{@code
  72  *     InvocationHandler handler = new MyInvocationHandler(...);
  73  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  74  *                                          new Class<?>[] { Foo.class },

 423                 checkProxyAccess(caller, loader, intf);
 424             }
 425             return proxyCache.sub(intf).computeIfAbsent(
 426                 loader,
 427                 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
 428             );
 429         } else {
 430             // interfaces cloned
 431             final Class<?>[] intfsArray = interfaces.clone();
 432             if (caller != null) {
 433                 checkProxyAccess(caller, loader, intfsArray);
 434             }
 435             final List<Class<?>> intfs = Arrays.asList(intfsArray);
 436             return proxyCache.sub(intfs).computeIfAbsent(
 437                 loader,
 438                 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
 439             );
 440         }
 441     }
 442 







 443     /*
 444      * Check permissions required to create a Proxy class.
 445      *
 446      * To define a proxy class, it performs the access checks as in
 447      * Class.forName (VM will invoke ClassLoader.checkPackageAccess):
 448      * 1. "getClassLoader" permission check if loader == null
 449      * 2. checkPackageAccess on the interfaces it implements
 450      *
 451      * To get a constructor and new instance of a proxy class, it performs
 452      * the package access check on the interfaces it implements
 453      * as in Class.getConstructor.
 454      *
 455      * If an interface is non-public, the proxy class must be defined by
 456      * the defining loader of the interface.  If the caller's class loader
 457      * is not the same as the defining loader of the interface, the VM
 458      * will throw IllegalAccessError when the generated proxy class is
 459      * being defined.
 460      */
 461     private static void checkProxyAccess(Class<?> caller,
 462                                          ClassLoader loader,

 466         SecurityManager sm = System.getSecurityManager();
 467         if (sm != null) {
 468             ClassLoader ccl = caller.getClassLoader();
 469             if (loader == null && ccl != null) {
 470                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
 471             }
 472             ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
 473         }
 474     }
 475 
 476     /**
 477      * Builder for a proxy class.
 478      *
 479      * If the module is not specified in this ProxyBuilder constructor,
 480      * it will map from the given loader and interfaces to the module
 481      * in which the proxy class will be defined.
 482      */
 483     private static final class ProxyBuilder {
 484         private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 485 













 486         // prefix for all proxy class names
 487         private static final String proxyClassNamePrefix = "$Proxy";
 488 
 489         // next number to use for generation of unique proxy class names
 490         private static final AtomicLong nextUniqueNumber = new AtomicLong();
 491 
 492         // a reverse cache of defined proxy classes
 493         private static final ClassLoaderValue<Boolean> reverseProxyCache =
 494             new ClassLoaderValue<>();
 495 
 496         private record ProxyClassContext(Module module, String packageName, int accessFlags) {
 497             private ProxyClassContext {
 498                 if (module.isNamed()) {
 499                     if (packageName.isEmpty()) {
 500                         // Per JLS 7.4.2, unnamed package can only exist in unnamed modules.
 501                         // This means a package-private superinterface exist in the unnamed
 502                         // package of a named module.
 503                         throw new InternalError("Unnamed package cannot be added to " + module);
 504                     }
 505 
 506                     if (!module.getDescriptor().packages().contains(packageName)) {
 507                         throw new InternalError(packageName + " not exist in " + module.getName());
 508                     }
 509 
 510                     if (!module.isOpen(packageName, Proxy.class.getModule())) {
 511                         // Required for default method invocation
 512                         throw new InternalError(packageName + " not open to " + Proxy.class.getModule());
 513                     }
 514                 } else {
 515                     if (Modifier.isPublic(accessFlags)) {
 516                         // All proxy superinterfaces are public, must be in named dynamic module
 517                         throw new InternalError("public proxy in unnamed module: " + module);
 518                     }
 519                 }
 520 
 521                 if ((accessFlags & ~Modifier.PUBLIC) != 0) {
 522                     throw new InternalError("proxy access flags must be Modifier.PUBLIC or 0");
 523                 }
 524             }
 525         }
 526 
 527         private static Class<?> defineProxyClass(ProxyClassContext context, List<Class<?>> interfaces) {
 528             /*
 529              * Choose a name for the proxy class to generate.
 530              */














 531             long num = nextUniqueNumber.getAndIncrement();
 532             String proxyName = context.packageName().isEmpty()
 533                                     ? proxyClassNamePrefix + num
 534                                     : context.packageName() + "." + proxyClassNamePrefix + num;
 535 
 536             ClassLoader loader = getLoader(context.module());
 537             trace(proxyName, context.module(), loader, interfaces);
 538 




 539             /*
 540              * Generate the specified proxy class.
 541              */
 542             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces,
 543                                                                       context.accessFlags() | Modifier.FINAL);
 544             try {
 545                 Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
 546                                               null, "__dynamic_proxy__");
 547                 reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
 548                 return pc;
 549             } catch (ClassFormatError e) {
 550                 /*
 551                  * A ClassFormatError here means that (barring bugs in the
 552                  * proxy class generation code) there was some other
 553                  * invalid aspect of the arguments supplied to the proxy
 554                  * class creation (such as virtual machine limitations
 555                  * exceeded).
 556                  */
 557                 throw new IllegalArgumentException(e.toString());
 558             }
 559         }
 560 

















 561         /**
 562          * Test if given class is a class defined by
 563          * {@link #defineProxyClass(ProxyClassContext, List)}
 564          */
 565         static boolean isProxyClass(Class<?> c) {
 566             return Objects.equals(reverseProxyCache.sub(c).get(c.getClassLoader()),
 567                                   Boolean.TRUE);
 568         }
 569 
 570         private static boolean isExportedType(Class<?> c) {
 571             String pn = c.getPackageName();
 572             return Modifier.isPublic(c.getModifiers()) && c.getModule().isExported(pn);
 573         }
 574 
 575         private static boolean isPackagePrivateType(Class<?> c) {
 576             return !Modifier.isPublic(c.getModifiers());
 577         }
 578 
 579         private static String toDetails(Class<?> c) {
 580             String access = "unknown";

 814 
 815                     targetModule = m;
 816                     targetPackageName = e.getKey().getPackageName();
 817                 }
 818 
 819                 // validate if the target module can access all other interfaces
 820                 for (Class<?> intf : interfaces) {
 821                     Module m = intf.getModule();
 822                     if (m == targetModule) continue;
 823 
 824                     if (!targetModule.canRead(m) || !m.isExported(intf.getPackageName(), targetModule)) {
 825                         throw new IllegalArgumentException(targetModule + " can't access " + intf.getName());
 826                     }
 827                 }
 828 
 829                 // opens the package of the non-public proxy class for java.base to access
 830                 if (targetModule.isNamed()) {
 831                     Modules.addOpens(targetModule, targetPackageName, Proxy.class.getModule());
 832                 }
 833                 // return the module of the package-private interface
 834                 return new ProxyClassContext(targetModule, targetPackageName, 0);
 835             }
 836 
 837             // All proxy interfaces are public.  So maps to a dynamic proxy module
 838             // and add reads edge and qualified exports, if necessary
 839             Module targetModule = getDynamicModule(loader);
 840 
 841             // set up proxy class access to proxy interfaces and types
 842             // referenced in the method signature
 843             Set<Class<?>> types = new HashSet<>(interfaces);
 844             types.addAll(refTypes);
 845             for (Class<?> c : types) {
 846                 ensureAccess(targetModule, c);
 847             }
 848 
 849             var pkgName = nonExported ? PROXY_PACKAGE_PREFIX + '.' + targetModule.getName()
 850                                       : targetModule.getName();
 851             return new ProxyClassContext(targetModule, pkgName, Modifier.PUBLIC);
 852         }
 853 
 854         /*
 855          * Ensure the given module can access the given class.
 856          */
 857         private static void ensureAccess(Module target, Class<?> c) {
 858             Module m = c.getModule();
 859             // add read edge and qualified export for the target module to access
 860             if (!target.canRead(m)) {
 861                 Modules.addReads(target, m);
 862             }
 863             String pn = c.getPackageName();
 864             if (!m.isExported(pn, target)) {
 865                 Modules.addExports(m, pn, target);
 866             }
 867         }
 868 
 869         /*
 870          * Ensure the given class is visible to the class loader.
 871          */

 886             while (e.isArray()) {
 887                 e = e.getComponentType();
 888             }
 889             return e;
 890         }
 891 
 892         private static final ClassLoaderValue<Module> dynProxyModules =
 893             new ClassLoaderValue<>();
 894         private static final AtomicInteger counter = new AtomicInteger();
 895 
 896         /*
 897          * Define a dynamic module with a package named $MODULE which
 898          * is unconditionally exported and another package named
 899          * com.sun.proxy.$MODULE which is encapsulated.
 900          *
 901          * Each class loader will have one dynamic module.
 902          */
 903         private static Module getDynamicModule(ClassLoader loader) {
 904             return dynProxyModules.computeIfAbsent(loader, (ld, clv) -> {
 905                 // create a dynamic module and setup module access
 906                 String mn = "jdk.proxy" + counter.incrementAndGet();

 907                 String pn = PROXY_PACKAGE_PREFIX + "." + mn;
 908                 ModuleDescriptor descriptor =
 909                         ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
 910                                         .packages(Set.of(pn, mn))
 911                                         .exports(mn)
 912                                         .build();
 913                 Module m = Modules.defineModule(ld, descriptor, null);
 914                 Modules.addReads(m, Proxy.class.getModule());
 915                 Modules.addExports(m, mn);
 916                 // java.base to create proxy instance and access its Lookup instance
 917                 Modules.addOpens(m, pn, Proxy.class.getModule());
 918                 Modules.addOpens(m, mn, Proxy.class.getModule());
 919                 return m;
 920             });
 921         }



















































































































































 922     }
 923 
 924     /**
 925      * Returns a proxy instance for the specified interfaces
 926      * that dispatches method invocations to the specified invocation
 927      * handler.
 928      * <p>
 929      * <a id="restrictions">{@code IllegalArgumentException} will be thrown
 930      * if any of the following restrictions is violated:</a>
 931      * <ul>
 932      * <li>All of {@code Class} objects in the given {@code interfaces} array
 933      * must represent {@linkplain Class#isHidden() non-hidden} and
 934      * {@linkplain Class#isSealed() non-sealed} interfaces,
 935      * not classes or primitive types.
 936      *
 937      * <li>No two elements in the {@code interfaces} array may
 938      * refer to identical {@code Class} objects.
 939      *
 940      * <li>All of the interface types must be visible by name through the
 941      * specified class loader. In other words, for class loader

  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.security.AccessController;
  34 import java.security.PrivilegedAction;
  35 import java.util.ArrayDeque;
  36 import java.util.ArrayList;
  37 import java.util.Arrays;
  38 import java.util.Collections;
  39 import java.util.Deque;
  40 import java.util.HashMap;
  41 import java.util.HashSet;
  42 import java.util.IdentityHashMap;
  43 import java.util.List;
  44 import java.util.Map;
  45 import java.util.Objects;
  46 import java.util.Set;
  47 import java.util.concurrent.ConcurrentHashMap;
  48 import java.util.concurrent.atomic.AtomicInteger;
  49 import java.util.concurrent.atomic.AtomicLong;
  50 import java.util.function.BooleanSupplier;
  51 
  52 import jdk.internal.access.JavaLangAccess;
  53 import jdk.internal.access.SharedSecrets;
  54 import jdk.internal.module.Modules;
  55 import jdk.internal.misc.VM;
  56 import jdk.internal.misc.CDS;
  57 import jdk.internal.reflect.CallerSensitive;
  58 import jdk.internal.reflect.Reflection;
  59 import jdk.internal.loader.ClassLoaderValue;
  60 import jdk.internal.vm.annotation.Stable;
  61 import sun.reflect.misc.ReflectUtil;
  62 import sun.security.action.GetPropertyAction;
  63 import sun.security.util.SecurityConstants;
  64 
  65 import static java.lang.invoke.MethodType.methodType;
  66 import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
  67 
  68 /**
  69  *
  70  * {@code Proxy} provides static methods for creating objects that act like instances
  71  * of interfaces but allow for customized method invocation.
  72  * To create a proxy instance for some interface {@code Foo}:
  73  * <pre>{@code
  74  *     InvocationHandler handler = new MyInvocationHandler(...);
  75  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  76  *                                          new Class<?>[] { Foo.class },

 425                 checkProxyAccess(caller, loader, intf);
 426             }
 427             return proxyCache.sub(intf).computeIfAbsent(
 428                 loader,
 429                 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
 430             );
 431         } else {
 432             // interfaces cloned
 433             final Class<?>[] intfsArray = interfaces.clone();
 434             if (caller != null) {
 435                 checkProxyAccess(caller, loader, intfsArray);
 436             }
 437             final List<Class<?>> intfs = Arrays.asList(intfsArray);
 438             return proxyCache.sub(intfs).computeIfAbsent(
 439                 loader,
 440                 (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
 441             );
 442         }
 443     }
 444 
 445     /**
 446      * Called from VM native code during dump time.
 447      */
 448     private static void initCacheForCDS(ClassLoader platformLoader, ClassLoader appLoader) {
 449         ProxyBuilder.initCacheForCDS(platformLoader, appLoader);
 450     }
 451 
 452     /*
 453      * Check permissions required to create a Proxy class.
 454      *
 455      * To define a proxy class, it performs the access checks as in
 456      * Class.forName (VM will invoke ClassLoader.checkPackageAccess):
 457      * 1. "getClassLoader" permission check if loader == null
 458      * 2. checkPackageAccess on the interfaces it implements
 459      *
 460      * To get a constructor and new instance of a proxy class, it performs
 461      * the package access check on the interfaces it implements
 462      * as in Class.getConstructor.
 463      *
 464      * If an interface is non-public, the proxy class must be defined by
 465      * the defining loader of the interface.  If the caller's class loader
 466      * is not the same as the defining loader of the interface, the VM
 467      * will throw IllegalAccessError when the generated proxy class is
 468      * being defined.
 469      */
 470     private static void checkProxyAccess(Class<?> caller,
 471                                          ClassLoader loader,

 475         SecurityManager sm = System.getSecurityManager();
 476         if (sm != null) {
 477             ClassLoader ccl = caller.getClassLoader();
 478             if (loader == null && ccl != null) {
 479                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
 480             }
 481             ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
 482         }
 483     }
 484 
 485     /**
 486      * Builder for a proxy class.
 487      *
 488      * If the module is not specified in this ProxyBuilder constructor,
 489      * it will map from the given loader and interfaces to the module
 490      * in which the proxy class will be defined.
 491      */
 492     private static final class ProxyBuilder {
 493         private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 494 
 495         private static String makeProxyClassNamePrefix() {
 496             // Allow unique proxy names to be used across CDS dump time and app run time.
 497             if (CDS.isDumpingArchive()) {
 498                 if (CDS.isUsingArchive()) {
 499                     return "$Proxy0100"; // CDS dynamic dump
 500                 } else {
 501                     return "$Proxy0010"; // CDS static dump
 502                 }
 503             } else {
 504                 return "$Proxy";
 505             }
 506         }
 507 
 508         // prefix for all proxy class names
 509         private static final String proxyClassNamePrefix = makeProxyClassNamePrefix();
 510 
 511         // next number to use for generation of unique proxy class names
 512         private static final AtomicLong nextUniqueNumber = new AtomicLong();
 513 
 514         // a reverse cache of defined proxy classes
 515         private static final ClassLoaderValue<Boolean> reverseProxyCache =
 516             new ClassLoaderValue<>();
 517 
 518         private record ProxyClassContext(Module module, String packageName, int accessFlags, boolean isDynamicModule) {
 519             private ProxyClassContext {
 520                 if (module.isNamed()) {
 521                     if (packageName.isEmpty()) {
 522                         // Per JLS 7.4.2, unnamed package can only exist in unnamed modules.
 523                         // This means a package-private superinterface exist in the unnamed
 524                         // package of a named module.
 525                         throw new InternalError("Unnamed package cannot be added to " + module);
 526                     }
 527 
 528                     if (!module.getDescriptor().packages().contains(packageName)) {
 529                         throw new InternalError(packageName + " not exist in " + module.getName());
 530                     }
 531 
 532                     if (!module.isOpen(packageName, Proxy.class.getModule())) {
 533                         // Required for default method invocation
 534                         throw new InternalError(packageName + " not open to " + Proxy.class.getModule());
 535                     }
 536                 } else {
 537                     if (Modifier.isPublic(accessFlags)) {
 538                         // All proxy superinterfaces are public, must be in named dynamic module
 539                         throw new InternalError("public proxy in unnamed module: " + module);
 540                     }
 541                 }
 542 
 543                 if ((accessFlags & ~Modifier.PUBLIC) != 0) {
 544                     throw new InternalError("proxy access flags must be Modifier.PUBLIC or 0");
 545                 }
 546             }
 547         }
 548 
 549         private static Class<?> defineProxyClass(ProxyClassContext context, List<Class<?>> interfaces) {
 550             /*
 551              * Choose a name for the proxy class to generate.
 552              */
 553             String packagePrefix = context.packageName().isEmpty()
 554                                     ? proxyClassNamePrefix
 555                                     : context.packageName() + "." + proxyClassNamePrefix;
 556             ClassLoader loader = getLoader(context.module());
 557             int accessFlags = context.accessFlags() | Modifier.FINAL;
 558 
 559             if (archivedData != null) {
 560                 Class<?> pc = archivedData.getArchivedProxyClass(loader, packagePrefix, interfaces);
 561                 if (pc != null) {
 562                     reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
 563                     return pc;
 564                 }
 565             }
 566 
 567             long num = nextUniqueNumber.getAndIncrement();
 568             String proxyName = packagePrefix + num;


 569 

 570             trace(proxyName, context.module(), loader, interfaces);
 571 
 572             if (CDS.isLoggingDynamicProxies() && context.isDynamicModule()) {
 573                 CDS.logDynamicProxy(loader, proxyName, interfaces.toArray(new Class<?>[0]), accessFlags);
 574             }
 575 
 576             /*
 577              * Generate the specified proxy class.
 578              */
 579             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);

 580             try {
 581                 Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
 582                                               null, "__dynamic_proxy__");
 583                 reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
 584                 return pc;
 585             } catch (ClassFormatError e) {
 586                 /*
 587                  * A ClassFormatError here means that (barring bugs in the
 588                  * proxy class generation code) there was some other
 589                  * invalid aspect of the arguments supplied to the proxy
 590                  * class creation (such as virtual machine limitations
 591                  * exceeded).
 592                  */
 593                 throw new IllegalArgumentException(e.toString());
 594             }
 595         }
 596 
 597         /**
 598          * Called from VM native code to define a proxy class to be stored in archivedData.
 599          */
 600         private static Class<?> defineProxyClassForCDS(ClassLoader loader, String proxyName, Class<?>[] interfaces,
 601                                                        int accessFlags) {
 602             ArrayList<Class<?>> list = new ArrayList<>();
 603             for (Object o : interfaces) {
 604                 list.add((Class<?>)o);
 605             }
 606 
 607             ProxyBuilder builder = new ProxyBuilder(loader, list);
 608             Constructor<?> cons = builder.build();
 609             Class<?> proxyClass = cons.getDeclaringClass();
 610             archivedData.putArchivedProxyClass(loader, proxyName, list, proxyClass);
 611             return proxyClass;
 612         }
 613 
 614         /**
 615          * Test if given class is a class defined by
 616          * {@link #defineProxyClass(ProxyClassContext, List)}
 617          */
 618         static boolean isProxyClass(Class<?> c) {
 619             return Objects.equals(reverseProxyCache.sub(c).get(c.getClassLoader()),
 620                                   Boolean.TRUE);
 621         }
 622 
 623         private static boolean isExportedType(Class<?> c) {
 624             String pn = c.getPackageName();
 625             return Modifier.isPublic(c.getModifiers()) && c.getModule().isExported(pn);
 626         }
 627 
 628         private static boolean isPackagePrivateType(Class<?> c) {
 629             return !Modifier.isPublic(c.getModifiers());
 630         }
 631 
 632         private static String toDetails(Class<?> c) {
 633             String access = "unknown";

 867 
 868                     targetModule = m;
 869                     targetPackageName = e.getKey().getPackageName();
 870                 }
 871 
 872                 // validate if the target module can access all other interfaces
 873                 for (Class<?> intf : interfaces) {
 874                     Module m = intf.getModule();
 875                     if (m == targetModule) continue;
 876 
 877                     if (!targetModule.canRead(m) || !m.isExported(intf.getPackageName(), targetModule)) {
 878                         throw new IllegalArgumentException(targetModule + " can't access " + intf.getName());
 879                     }
 880                 }
 881 
 882                 // opens the package of the non-public proxy class for java.base to access
 883                 if (targetModule.isNamed()) {
 884                     Modules.addOpens(targetModule, targetPackageName, Proxy.class.getModule());
 885                 }
 886                 // return the module of the package-private interface
 887                 return new ProxyClassContext(targetModule, targetPackageName, 0, false);
 888             }
 889 
 890             // All proxy interfaces are public.  So maps to a dynamic proxy module
 891             // and add reads edge and qualified exports, if necessary
 892             Module targetModule = getDynamicModule(loader);
 893 
 894             // set up proxy class access to proxy interfaces and types
 895             // referenced in the method signature
 896             Set<Class<?>> types = new HashSet<>(interfaces);
 897             types.addAll(refTypes);
 898             for (Class<?> c : types) {
 899                 ensureAccess(targetModule, c);
 900             }
 901 
 902             var pkgName = nonExported ? PROXY_PACKAGE_PREFIX + '.' + targetModule.getName()
 903                                       : targetModule.getName();
 904             return new ProxyClassContext(targetModule, pkgName, Modifier.PUBLIC, true);
 905         }
 906 
 907         /*
 908          * Ensure the given module can access the given class.
 909          */
 910         private static void ensureAccess(Module target, Class<?> c) {
 911             Module m = c.getModule();
 912             // add read edge and qualified export for the target module to access
 913             if (!target.canRead(m)) {
 914                 Modules.addReads(target, m);
 915             }
 916             String pn = c.getPackageName();
 917             if (!m.isExported(pn, target)) {
 918                 Modules.addExports(m, pn, target);
 919             }
 920         }
 921 
 922         /*
 923          * Ensure the given class is visible to the class loader.
 924          */

 939             while (e.isArray()) {
 940                 e = e.getComponentType();
 941             }
 942             return e;
 943         }
 944 
 945         private static final ClassLoaderValue<Module> dynProxyModules =
 946             new ClassLoaderValue<>();
 947         private static final AtomicInteger counter = new AtomicInteger();
 948 
 949         /*
 950          * Define a dynamic module with a package named $MODULE which
 951          * is unconditionally exported and another package named
 952          * com.sun.proxy.$MODULE which is encapsulated.
 953          *
 954          * Each class loader will have one dynamic module.
 955          */
 956         private static Module getDynamicModule(ClassLoader loader) {
 957             return dynProxyModules.computeIfAbsent(loader, (ld, clv) -> {
 958                 // create a dynamic module and setup module access
 959                 int num = counter.incrementAndGet();
 960                 String mn = "jdk.proxy" + num;
 961                 String pn = PROXY_PACKAGE_PREFIX + "." + mn;
 962                 ModuleDescriptor descriptor =
 963                         ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
 964                                         .packages(Set.of(pn, mn))
 965                                         .exports(mn)
 966                                         .build();
 967                 Module m = Modules.defineModule(ld, descriptor, null);
 968                 openDynamicModule(m);
 969 
 970                 if (CDS.isDumpingHeap() && archivedData != null) {
 971                     archivedData.recordModule(loader, m, num);
 972                 }
 973                 return m;
 974             });
 975         }
 976 
 977         private static void openDynamicModule(Module m) {
 978             String mn = m.getName();
 979             String pn = PROXY_PACKAGE_PREFIX + "." + mn;
 980             Modules.addReads(m, Proxy.class.getModule());
 981             Modules.addExports(m, mn);
 982             // java.base to create proxy instance and access its Lookup instance
 983             Modules.addOpens(m, pn, Proxy.class.getModule());
 984             Modules.addOpens(m, mn, Proxy.class.getModule());
 985         }
 986 
 987         static class ArchivedData {
 988             static class InterfacesKey {
 989                 Class<?>[] intfsArray;
 990                 InterfacesKey(List<Class<?>> intfs) {
 991                     intfsArray = new Class<?>[intfs.size()];
 992                     for (int i = 0; i < intfs.size(); i++) {
 993                         intfsArray[i] = intfs.get(i);
 994                     }
 995                 }
 996                 @Override
 997                 public int hashCode() {
 998                     return Arrays.hashCode(intfsArray);
 999                 }
1000                 @Override
1001                 public boolean equals(Object other) {
1002                     if (other instanceof InterfacesKey) {
1003                         InterfacesKey o = (InterfacesKey)other;
1004                         int len = intfsArray.length;
1005                         if (len != o.intfsArray.length) {
1006                             return false;
1007                         }
1008                         Class<?>[] oa = o.intfsArray;
1009                         for (int i = 0; i < len; i++) {
1010                             if (intfsArray[i] != oa[i]) {
1011                                 return false;
1012                             }
1013                         }
1014                         return true;
1015                     } else {
1016                         return false;
1017                     }
1018                 }
1019             }
1020 
1021             ClassLoader platformLoader;
1022             ClassLoader appLoader;
1023             HashMap<InterfacesKey,Class<?>> bootCache = new HashMap<>();
1024             HashMap<InterfacesKey,Class<?>> platformCache = new HashMap<>();
1025             HashMap<InterfacesKey,Class<?>> appCache = new HashMap<>();
1026 
1027             Module bootModule;
1028             Module platformModule;
1029             Module appModule;
1030             int maxNum;
1031 
1032             ArchivedData(ClassLoader plat, ClassLoader app) {
1033                 platformLoader = plat;
1034                 appLoader = app;
1035             }
1036 
1037             HashMap<InterfacesKey,Class<?>> cacheForLoader(ClassLoader loader) {
1038                 if (loader == null) {
1039                     return bootCache;
1040                 } else if (loader == platformLoader) {
1041                     return platformCache;
1042                 } else if (loader == appLoader) {
1043                     return appCache;
1044                 } else {
1045                     return null;
1046                 }
1047             }
1048 
1049             void recordModule(ClassLoader loader, Module m, int num) {
1050                 if (loader == null) {
1051                     bootModule = m;
1052                 } else if (loader == platformLoader) {
1053                     platformModule = m;
1054                 } else if (loader == appLoader) {
1055                     appModule = m;
1056                 } else {
1057                     throw new UnsupportedOperationException("Class loader " + loader + " is not supported");
1058                 }
1059                 if (maxNum < num) {
1060                     maxNum = num;
1061                 }
1062             }
1063 
1064             void restore() {
1065                 // The info for addReads/addExports/addOpens are maintained solely inside the VM.
1066                 // CDS currently doesn't properly archive such info for the dynamically generated modules,
1067                 // so we have to recreate them at runtime.
1068                 //
1069                 // TODO --  consider improving CDS to archive the above info, so we can avoid calling openDynamicModule()
1070                 if (bootModule != null) {
1071                     Module last = dynProxyModules.putIfAbsent(null, bootModule);
1072                     assert last == null;
1073                     openDynamicModule(bootModule);
1074                 }
1075                 if (platformModule != null) {
1076                     Module last = dynProxyModules.putIfAbsent(platformLoader, platformModule);
1077                     assert last == null;
1078                     openDynamicModule(platformModule);
1079                 }
1080                 if (appModule != null) {
1081                     Module last = dynProxyModules.putIfAbsent(appLoader, appModule);
1082                     assert last == null;
1083                     openDynamicModule(appModule);
1084                 }
1085 
1086                 while (maxNum > counter.get()) {
1087                     counter.incrementAndGet();
1088                 }
1089             }
1090 
1091 
1092             Class<?> getArchivedProxyClass(ClassLoader loader, String proxyPrefix, List<Class<?>> interfaces) {
1093                 HashMap<InterfacesKey,Class<?>> cache = cacheForLoader(loader);
1094                 if (cache != null && cache.size() > 0) {
1095                     InterfacesKey key = new InterfacesKey(interfaces);
1096                     return cache.get(key);
1097                 } else {
1098                     return null;
1099                 }
1100             }
1101 
1102             void putArchivedProxyClass(ClassLoader loader, String proxyName, List<Class<?>> interfaces, Class<?> cls) {
1103                 HashMap<InterfacesKey,Class<?>> cache = cacheForLoader(loader);
1104                 if (cache != null) {
1105                     InterfacesKey key = new InterfacesKey(interfaces);
1106                     cache.put(key, cls);
1107                 }
1108             }
1109         }
1110 
1111         static ArchivedData archivedData;
1112 
1113         static {
1114             CDS.initializeFromArchive(ProxyBuilder.class);
1115             if (archivedData != null) {
1116                 archivedData.restore();
1117             }
1118         }
1119 
1120         private static void initCacheForCDS(ClassLoader platformLoader, ClassLoader appLoader) {
1121             archivedData = new ArchivedData(platformLoader, appLoader);
1122         }
1123     }
1124 
1125     /**
1126      * Returns a proxy instance for the specified interfaces
1127      * that dispatches method invocations to the specified invocation
1128      * handler.
1129      * <p>
1130      * <a id="restrictions">{@code IllegalArgumentException} will be thrown
1131      * if any of the following restrictions is violated:</a>
1132      * <ul>
1133      * <li>All of {@code Class} objects in the given {@code interfaces} array
1134      * must represent {@linkplain Class#isHidden() non-hidden} and
1135      * {@linkplain Class#isSealed() non-sealed} interfaces,
1136      * not classes or primitive types.
1137      *
1138      * <li>No two elements in the {@code interfaces} array may
1139      * refer to identical {@code Class} objects.
1140      *
1141      * <li>All of the interface types must be visible by name through the
1142      * specified class loader. In other words, for class loader
< prev index next >