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
|