< 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";

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

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

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



















































































































































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

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

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