< 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             if (target == m) return;
 860 
 861             // add read edge and qualified export for the target module to access
 862             if (!target.canRead(m)) {
 863                 Modules.addReads(target, m);
 864             }
 865             String pn = c.getPackageName();
 866             if (!m.isExported(pn, target)) {
 867                 Modules.addExports(m, pn, target);
 868             }
 869         }
 870 
 871         /*

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

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



















































































































































 924     }
 925 
 926     /**
 927      * Returns a proxy instance for the specified interfaces
 928      * that dispatches method invocations to the specified invocation
 929      * handler.
 930      * <p>
 931      * <a id="restrictions">{@code IllegalArgumentException} will be thrown
 932      * if any of the following restrictions is violated:</a>
 933      * <ul>
 934      * <li>All of {@code Class} objects in the given {@code interfaces} array
 935      * must represent {@linkplain Class#isHidden() non-hidden} and
 936      * {@linkplain Class#isSealed() non-sealed} interfaces,
 937      * not classes or primitive types.
 938      *
 939      * <li>No two elements in the {@code interfaces} array may
 940      * refer to identical {@code Class} objects.
 941      *
 942      * <li>All of the interface types must be visible by name through the
 943      * 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             if (target == m) return;
 913 
 914             // add read edge and qualified export for the target module to access
 915             if (!target.canRead(m)) {
 916                 Modules.addReads(target, m);
 917             }
 918             String pn = c.getPackageName();
 919             if (!m.isExported(pn, target)) {
 920                 Modules.addExports(m, pn, target);
 921             }
 922         }
 923 
 924         /*

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