1 /*
2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
342 * @throws IllegalArgumentException if any of the <a href="#restrictions">
343 * restrictions</a> on the parameters are violated
344 * @throws SecurityException if a security manager, <em>s</em>, is present
345 * and any of the following conditions is met:
346 * <ul>
347 * <li> the given {@code loader} is {@code null} and
348 * the caller's class loader is not {@code null} and the
349 * invocation of {@link SecurityManager#checkPermission
350 * s.checkPermission} with
351 * {@code RuntimePermission("getClassLoader")} permission
352 * denies access.</li>
353 * <li> for each proxy interface, {@code intf},
354 * the caller's class loader is not the same as or an
355 * ancestor of the class loader for {@code intf} and
356 * invocation of {@link SecurityManager#checkPackageAccess
357 * s.checkPackageAccess()} denies access to {@code intf}.</li>
358 * </ul>
359 * @throws NullPointerException if the {@code interfaces} array
360 * argument or any of its elements are {@code null}
361 *
362 * @deprecated Proxy classes generated in a named module are encapsulated and not
363 * accessible to code outside its module.
364 * {@link Constructor#newInstance(Object...) Constructor.newInstance} will throw
365 * {@code IllegalAccessException} when it is called on an inaccessible proxy class.
366 * Use {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
367 * to create a proxy instance instead.
368 *
369 * @see <a href="#membership">Package and Module Membership of Proxy Class</a>
370 * @revised 9
371 * @spec JPMS
372 */
373 @Deprecated
374 @CallerSensitive
375 public static Class<?> getProxyClass(ClassLoader loader,
376 Class<?>... interfaces)
377 throws IllegalArgumentException
378 {
379 Class<?> caller = System.getSecurityManager() == null
380 ? null
381 : Reflection.getCallerClass();
382
383 return getProxyConstructor(caller, loader, interfaces)
384 .getDeclaringClass();
385 }
494 accessFlags = Modifier.FINAL; // non-public, final
495 String pkg = intf.getPackageName();
496 if (proxyPkg == null) {
497 proxyPkg = pkg;
498 } else if (!pkg.equals(proxyPkg)) {
499 throw new IllegalArgumentException(
500 "non-public interfaces from different packages");
501 }
502 }
503 }
504
505 if (proxyPkg == null) {
506 // all proxy interfaces are public
507 proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
508 : PROXY_PACKAGE_PREFIX;
509 } else if (proxyPkg.isEmpty() && m.isNamed()) {
510 throw new IllegalArgumentException(
511 "Unnamed package cannot be added to " + m);
512 }
513
514 // add the package to the runtime module if not exists
515 if (m.isNamed()) {
516 m.addPackage(proxyPkg);
517 }
518
519 /*
520 * Choose a name for the proxy class to generate.
521 */
522 long num = nextUniqueNumber.getAndIncrement();
523 String proxyName = proxyPkg.isEmpty() ? proxyClassNamePrefix + num
524 : proxyPkg + "." + proxyClassNamePrefix + num;
525
526 ClassLoader loader = getLoader(m);
527 trace(proxyName, m, loader, interfaces);
528
529 /*
530 * Generate the specified proxy class.
531 */
532 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
533 proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
534 try {
535 Class<?> pc = UNSAFE.defineClass(proxyName, proxyClassFile,
536 0, proxyClassFile.length,
537 loader, null);
538 reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
539 return pc;
540 } catch (ClassFormatError e) {
541 /*
542 * A ClassFormatError here means that (barring bugs in the
543 * proxy class generation code) there was some other
564 }
565
566 private static boolean isPackagePrivateType(Class<?> c) {
567 return !Modifier.isPublic(c.getModifiers());
568 }
569
570 private static String toDetails(Class<?> c) {
571 String access = "unknown";
572 if (isExportedType(c)) {
573 access = "exported";
574 } else if (isPackagePrivateType(c)) {
575 access = "package-private";
576 } else {
577 access = "module-private";
578 }
579 ClassLoader ld = c.getClassLoader();
580 return String.format(" %s/%s %s loader %s",
581 c.getModule().getName(), c.getName(), access, ld);
582 }
583
584 static void trace(String cn, Module module, ClassLoader loader, List<Class<?>> interfaces) {
585 if (isDebug()) {
586 System.out.format("PROXY: %s/%s defined by %s%n", module.getName(), cn, loader);
587 }
588 if (isDebug("debug")) {
589 interfaces.stream()
590 .forEach(c -> System.out.println(toDetails(c)));
591 }
592 }
593
594 private static final String DEBUG =
595 GetPropertyAction.privilegedGetProperty("jdk.proxy.debug", "");
596
597 private static boolean isDebug() {
598 return !DEBUG.isEmpty();
599 }
600 private static boolean isDebug(String flag) {
601 return DEBUG.equals(flag);
602 }
603
604 // ProxyBuilder instance members start here....
605
606 private final ClassLoader loader;
607 private final List<Class<?>> interfaces;
608 private final Module module;
609 ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
610 if (!VM.isModuleSystemInited()) {
611 throw new InternalError("Proxy is not supported until module system is fully initialized");
612 }
613 if (interfaces.size() > 65535) {
614 throw new IllegalArgumentException("interface limit exceeded: " + interfaces.size());
615 }
616
617 Set<Class<?>> refTypes = referencedTypes(loader, interfaces);
618
619 // IAE if violates any restrictions specified in newProxyInstance
620 validateProxyInterfaces(loader, interfaces, refTypes);
621
622 this.loader = loader;
623 this.interfaces = interfaces;
624 this.module = mapToModule(loader, interfaces, refTypes);
625 assert getLoader(module) == loader;
626 }
627
628 ProxyBuilder(ClassLoader loader, Class<?> intf) {
629 this(loader, Collections.singletonList(intf));
630 }
631
632 /**
633 * Generate a proxy class and return its proxy Constructor with
634 * accessible flag already set. If the target module does not have access
635 * to any interface types, IllegalAccessError will be thrown by the VM
636 * at defineClass time.
637 *
638 * Must call the checkProxyAccess method to perform permission checks
639 * before calling this.
640 */
641 Constructor<?> build() {
642 Class<?> proxyClass = defineProxyClass(module, interfaces);
643 final Constructor<?> cons;
644 try {
645 cons = proxyClass.getConstructor(constructorParams);
646 } catch (NoSuchMethodException e) {
647 throw new InternalError(e.toString(), e);
648 }
649 AccessController.doPrivileged(new PrivilegedAction<Void>() {
650 public Void run() {
651 cons.setAccessible(true);
652 return null;
653 }
654 });
655 return cons;
656 }
657
658 /**
659 * Validate the given proxy interfaces and the given referenced types
660 * are visible to the defining loader.
661 *
662 * @throws IllegalArgumentException if it violates the restrictions specified
663 * in {@link Proxy#newProxyInstance}
664 */
665 private static void validateProxyInterfaces(ClassLoader loader,
666 List<Class<?>> interfaces,
667 Set<Class<?>> refTypes)
668 {
669 Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.size());
670 for (Class<?> intf : interfaces) {
671 /*
672 * Verify that the class loader resolves the name of this
673 * interface to the same Class object.
674 */
675 ensureVisible(loader, intf);
676
677 /*
678 * Verify that the Class object actually represents an
679 * interface.
680 */
681 if (!intf.isInterface()) {
682 throw new IllegalArgumentException(intf.getName() + " is not an interface");
683 }
714 * Extracts all types referenced on a method signature including
715 * its return type, parameter types, and exception types.
716 */
717 private static Stream<Class<?>> methodRefTypes(Method m) {
718 return Stream.of(new Class<?>[] { m.getReturnType() },
719 m.getParameterTypes(),
720 m.getExceptionTypes())
721 .flatMap(Stream::of);
722 }
723
724 /**
725 * Returns the module that the generated proxy class belongs to.
726 *
727 * If all proxy interfaces are public and in exported packages,
728 * then the proxy class is in unnamed module.
729 *
730 * If any of proxy interface is package-private, then the proxy class
731 * is in the same module of the package-private interface.
732 *
733 * If all proxy interfaces are public and at least one in a non-exported
734 * package, then the proxy class is in a dynamic module in a non-exported
735 * package. Reads edge and qualified exports are added for
736 * dynamic module to access.
737 */
738 private static Module mapToModule(ClassLoader loader,
739 List<Class<?>> interfaces,
740 Set<Class<?>> refTypes) {
741 Map<Class<?>, Module> modulePrivateTypes = new HashMap<>();
742 Map<Class<?>, Module> packagePrivateTypes = new HashMap<>();
743 for (Class<?> intf : interfaces) {
744 Module m = intf.getModule();
745 if (Modifier.isPublic(intf.getModifiers())) {
746 // module-private types
747 if (!m.isExported(intf.getPackageName())) {
748 modulePrivateTypes.put(intf, m);
749 }
750 } else {
751 packagePrivateTypes.put(intf, m);
752 }
753 }
754
755 // all proxy interfaces are public and exported, the proxy class is in unnamed module
756 // Such proxy class is accessible to any unnamed module and named module that
757 // can read unnamed module
758 if (packagePrivateTypes.isEmpty() && modulePrivateTypes.isEmpty()) {
759 return loader != null ? loader.getUnnamedModule() : BootLoader.getUnnamedModule();
760 }
761
762 if (packagePrivateTypes.size() > 0) {
763 // all package-private types must be in the same runtime package
764 // i.e. same package name and same module (named or unnamed)
765 //
766 // Configuration will fail if M1 and in M2 defined by the same loader
767 // and both have the same package p (so no need to check class loader)
768 if (packagePrivateTypes.size() > 1 &&
769 (packagePrivateTypes.keySet().stream() // more than one package
770 .map(Class::getPackageName).distinct().count() > 1 ||
771 packagePrivateTypes.values().stream() // or more than one module
772 .distinct().count() > 1)) {
773 throw new IllegalArgumentException(
774 "non-public interfaces from different packages");
775 }
776
777 // all package-private types are in the same module (named or unnamed)
778 Module target = null;
779 for (Module m : packagePrivateTypes.values()) {
780 if (getLoader(m) != loader) {
781 // the specified loader is not the same class loader of the non-public interface
782 throw new IllegalArgumentException(
783 "non-public interface is not defined by the given loader");
784 }
785 target = m;
786 }
787
788 // validate if the target module can access all other interfaces
789 for (Class<?> intf : interfaces) {
790 Module m = intf.getModule();
791 if (m == target) continue;
792
793 if (!target.canRead(m) || !m.isExported(intf.getPackageName(), target)) {
794 throw new IllegalArgumentException(target + " can't access " + intf.getName());
795 }
796 }
797
798 // return the module of the package-private interface
799 return target;
800 }
801
802 // all proxy interfaces are public and at least one in a non-exported package
803 // map to dynamic proxy module and add reads edge and qualified exports, if necessary
804 Module target = getDynamicModule(loader);
805
806 // set up proxy class access to proxy interfaces and types
807 // referenced in the method signature
808 Set<Class<?>> types = new HashSet<>(interfaces);
809 types.addAll(refTypes);
810 for (Class<?> c : types) {
811 ensureAccess(target, c);
812 }
813 return target;
814 }
815
816 /*
817 * Ensure the given module can access the given class.
818 */
819 private static void ensureAccess(Module target, Class<?> c) {
820 Module m = c.getModule();
821 // add read edge and qualified export for the target module to access
822 if (!target.canRead(m)) {
823 Modules.addReads(target, m);
839 }
840 if (type != c) {
841 throw new IllegalArgumentException(c.getName() +
842 " referenced from a method is not visible from class loader");
843 }
844 }
845
846 private static Class<?> getElementType(Class<?> type) {
847 Class<?> e = type;
848 while (e.isArray()) {
849 e = e.getComponentType();
850 }
851 return e;
852 }
853
854 private static final ClassLoaderValue<Module> dynProxyModules =
855 new ClassLoaderValue<>();
856 private static final AtomicInteger counter = new AtomicInteger();
857
858 /*
859 * Define a dynamic module for the generated proxy classes in a non-exported package
860 * named com.sun.proxy.$MODULE.
861 *
862 * Each class loader will have one dynamic module.
863 */
864 private static Module getDynamicModule(ClassLoader loader) {
865 return dynProxyModules.computeIfAbsent(loader, (ld, clv) -> {
866 // create a dynamic module and setup module access
867 String mn = "jdk.proxy" + counter.incrementAndGet();
868 String pn = PROXY_PACKAGE_PREFIX + "." + mn;
869 ModuleDescriptor descriptor =
870 ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
871 .packages(Set.of(pn))
872 .build();
873 Module m = Modules.defineModule(ld, descriptor, null);
874 Modules.addReads(m, Proxy.class.getModule());
875 // java.base to create proxy instance
876 Modules.addExports(m, pn, Object.class.getModule());
877 return m;
878 });
879 }
880 }
|
1 /*
2 * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
342 * @throws IllegalArgumentException if any of the <a href="#restrictions">
343 * restrictions</a> on the parameters are violated
344 * @throws SecurityException if a security manager, <em>s</em>, is present
345 * and any of the following conditions is met:
346 * <ul>
347 * <li> the given {@code loader} is {@code null} and
348 * the caller's class loader is not {@code null} and the
349 * invocation of {@link SecurityManager#checkPermission
350 * s.checkPermission} with
351 * {@code RuntimePermission("getClassLoader")} permission
352 * denies access.</li>
353 * <li> for each proxy interface, {@code intf},
354 * the caller's class loader is not the same as or an
355 * ancestor of the class loader for {@code intf} and
356 * invocation of {@link SecurityManager#checkPackageAccess
357 * s.checkPackageAccess()} denies access to {@code intf}.</li>
358 * </ul>
359 * @throws NullPointerException if the {@code interfaces} array
360 * argument or any of its elements are {@code null}
361 *
362 * @deprecated Proxy classes generated in a named module are encapsulated
363 * and not accessible to code outside its module.
364 * {@link Constructor#newInstance(Object...) Constructor.newInstance}
365 * will throw {@code IllegalAccessException} when it is called on
366 * an inaccessible proxy class.
367 * Use {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
368 * to create a proxy instance instead.
369 *
370 * @see <a href="#membership">Package and Module Membership of Proxy Class</a>
371 * @revised 9
372 * @spec JPMS
373 */
374 @Deprecated
375 @CallerSensitive
376 public static Class<?> getProxyClass(ClassLoader loader,
377 Class<?>... interfaces)
378 throws IllegalArgumentException
379 {
380 Class<?> caller = System.getSecurityManager() == null
381 ? null
382 : Reflection.getCallerClass();
383
384 return getProxyConstructor(caller, loader, interfaces)
385 .getDeclaringClass();
386 }
495 accessFlags = Modifier.FINAL; // non-public, final
496 String pkg = intf.getPackageName();
497 if (proxyPkg == null) {
498 proxyPkg = pkg;
499 } else if (!pkg.equals(proxyPkg)) {
500 throw new IllegalArgumentException(
501 "non-public interfaces from different packages");
502 }
503 }
504 }
505
506 if (proxyPkg == null) {
507 // all proxy interfaces are public
508 proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
509 : PROXY_PACKAGE_PREFIX;
510 } else if (proxyPkg.isEmpty() && m.isNamed()) {
511 throw new IllegalArgumentException(
512 "Unnamed package cannot be added to " + m);
513 }
514
515 if (m.isNamed()) {
516 if (!m.getDescriptor().packages().contains(proxyPkg)) {
517 throw new InternalError(proxyPkg + " not exist in " + m.getName());
518 }
519 }
520
521 /*
522 * Choose a name for the proxy class to generate.
523 */
524 long num = nextUniqueNumber.getAndIncrement();
525 String proxyName = proxyPkg.isEmpty()
526 ? proxyClassNamePrefix + num
527 : proxyPkg + "." + proxyClassNamePrefix + num;
528
529 ClassLoader loader = getLoader(m);
530 trace(proxyName, m, loader, interfaces);
531
532 /*
533 * Generate the specified proxy class.
534 */
535 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
536 proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
537 try {
538 Class<?> pc = UNSAFE.defineClass(proxyName, proxyClassFile,
539 0, proxyClassFile.length,
540 loader, null);
541 reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
542 return pc;
543 } catch (ClassFormatError e) {
544 /*
545 * A ClassFormatError here means that (barring bugs in the
546 * proxy class generation code) there was some other
567 }
568
569 private static boolean isPackagePrivateType(Class<?> c) {
570 return !Modifier.isPublic(c.getModifiers());
571 }
572
573 private static String toDetails(Class<?> c) {
574 String access = "unknown";
575 if (isExportedType(c)) {
576 access = "exported";
577 } else if (isPackagePrivateType(c)) {
578 access = "package-private";
579 } else {
580 access = "module-private";
581 }
582 ClassLoader ld = c.getClassLoader();
583 return String.format(" %s/%s %s loader %s",
584 c.getModule().getName(), c.getName(), access, ld);
585 }
586
587 static void trace(String cn,
588 Module module,
589 ClassLoader loader,
590 List<Class<?>> interfaces) {
591 if (isDebug()) {
592 System.err.format("PROXY: %s/%s defined by %s%n",
593 module.getName(), cn, loader);
594 }
595 if (isDebug("debug")) {
596 interfaces.stream()
597 .forEach(c -> System.out.println(toDetails(c)));
598 }
599 }
600
601 private static final String DEBUG =
602 GetPropertyAction.privilegedGetProperty("jdk.proxy.debug", "");
603
604 private static boolean isDebug() {
605 return !DEBUG.isEmpty();
606 }
607 private static boolean isDebug(String flag) {
608 return DEBUG.equals(flag);
609 }
610
611 // ProxyBuilder instance members start here....
612
613 private final List<Class<?>> interfaces;
614 private final Module module;
615 ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
616 if (!VM.isModuleSystemInited()) {
617 throw new InternalError("Proxy is not supported until "
618 + "module system is fully initialized");
619 }
620 if (interfaces.size() > 65535) {
621 throw new IllegalArgumentException("interface limit exceeded: "
622 + interfaces.size());
623 }
624
625 Set<Class<?>> refTypes = referencedTypes(loader, interfaces);
626
627 // IAE if violates any restrictions specified in newProxyInstance
628 validateProxyInterfaces(loader, interfaces, refTypes);
629
630 this.interfaces = interfaces;
631 this.module = mapToModule(loader, interfaces, refTypes);
632 assert getLoader(module) == loader;
633 }
634
635 ProxyBuilder(ClassLoader loader, Class<?> intf) {
636 this(loader, Collections.singletonList(intf));
637 }
638
639 /**
640 * Generate a proxy class and return its proxy Constructor with
641 * accessible flag already set. If the target module does not have access
642 * to any interface types, IllegalAccessError will be thrown by the VM
643 * at defineClass time.
644 *
645 * Must call the checkProxyAccess method to perform permission checks
646 * before calling this.
647 */
648 Constructor<?> build() {
649 Class<?> proxyClass = defineProxyClass(module, interfaces);
650 final Constructor<?> cons;
651 try {
652 cons = proxyClass.getConstructor(constructorParams);
653 } catch (NoSuchMethodException e) {
654 throw new InternalError(e.toString(), e);
655 }
656 AccessController.doPrivileged(new PrivilegedAction<Void>() {
657 public Void run() {
658 cons.setAccessible(true);
659 return null;
660 }
661 });
662 return cons;
663 }
664
665 /**
666 * Validate the given proxy interfaces and the given referenced types
667 * are visible to the defining loader.
668 *
669 * @throws IllegalArgumentException if it violates the restrictions
670 * specified in {@link Proxy#newProxyInstance}
671 */
672 private static void validateProxyInterfaces(ClassLoader loader,
673 List<Class<?>> interfaces,
674 Set<Class<?>> refTypes)
675 {
676 Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.size());
677 for (Class<?> intf : interfaces) {
678 /*
679 * Verify that the class loader resolves the name of this
680 * interface to the same Class object.
681 */
682 ensureVisible(loader, intf);
683
684 /*
685 * Verify that the Class object actually represents an
686 * interface.
687 */
688 if (!intf.isInterface()) {
689 throw new IllegalArgumentException(intf.getName() + " is not an interface");
690 }
721 * Extracts all types referenced on a method signature including
722 * its return type, parameter types, and exception types.
723 */
724 private static Stream<Class<?>> methodRefTypes(Method m) {
725 return Stream.of(new Class<?>[] { m.getReturnType() },
726 m.getParameterTypes(),
727 m.getExceptionTypes())
728 .flatMap(Stream::of);
729 }
730
731 /**
732 * Returns the module that the generated proxy class belongs to.
733 *
734 * If all proxy interfaces are public and in exported packages,
735 * then the proxy class is in unnamed module.
736 *
737 * If any of proxy interface is package-private, then the proxy class
738 * is in the same module of the package-private interface.
739 *
740 * If all proxy interfaces are public and at least one in a non-exported
741 * package, then the proxy class is in a dynamic module in a
742 * non-exported package. Reads edge and qualified exports are added
743 * for dynamic module to access.
744 */
745 private static Module mapToModule(ClassLoader loader,
746 List<Class<?>> interfaces,
747 Set<Class<?>> refTypes) {
748 Map<Class<?>, Module> modulePrivateTypes = new HashMap<>();
749 Map<Class<?>, Module> packagePrivateTypes = new HashMap<>();
750 for (Class<?> intf : interfaces) {
751 Module m = intf.getModule();
752 if (Modifier.isPublic(intf.getModifiers())) {
753 // module-private types
754 if (!m.isExported(intf.getPackageName())) {
755 modulePrivateTypes.put(intf, m);
756 }
757 } else {
758 packagePrivateTypes.put(intf, m);
759 }
760 }
761
762 // all proxy interfaces are public and exported, the proxy class
763 // is in unnamed module. Such proxy class is accessible to
764 // any unnamed module and named module that can read unnamed module
765 if (packagePrivateTypes.isEmpty() && modulePrivateTypes.isEmpty()) {
766 return loader != null ? loader.getUnnamedModule()
767 : BootLoader.getUnnamedModule();
768 }
769
770 if (packagePrivateTypes.size() > 0) {
771 // all package-private types must be in the same runtime package
772 // i.e. same package name and same module (named or unnamed)
773 //
774 // Configuration will fail if M1 and in M2 defined by the same loader
775 // and both have the same package p (so no need to check class loader)
776 if (packagePrivateTypes.size() > 1 &&
777 (packagePrivateTypes.keySet().stream() // more than one package
778 .map(Class::getPackageName).distinct().count() > 1 ||
779 packagePrivateTypes.values().stream() // or more than one module
780 .distinct().count() > 1)) {
781 throw new IllegalArgumentException(
782 "non-public interfaces from different packages");
783 }
784
785 // all package-private types are in the same module (named or unnamed)
786 Module target = null;
787 for (Module m : packagePrivateTypes.values()) {
788 if (getLoader(m) != loader) {
789 // the specified loader is not the same class loader
790 // of the non-public interface
791 throw new IllegalArgumentException(
792 "non-public interface is not defined by the given loader");
793 }
794 target = m;
795 }
796
797 // validate if the target module can access all other interfaces
798 for (Class<?> intf : interfaces) {
799 Module m = intf.getModule();
800 if (m == target) continue;
801
802 if (!target.canRead(m) || !m.isExported(intf.getPackageName(), target)) {
803 throw new IllegalArgumentException(target + " can't access " + intf.getName());
804 }
805 }
806
807 // return the module of the package-private interface
808 return target;
809 }
810
811 // All proxy interfaces are public and at least one in a non-exported
812 // package. So maps to a dynamic proxy module and add reads edge
813 // and qualified exports, if necessary
814 Module target = getDynamicModule(loader);
815
816 // set up proxy class access to proxy interfaces and types
817 // referenced in the method signature
818 Set<Class<?>> types = new HashSet<>(interfaces);
819 types.addAll(refTypes);
820 for (Class<?> c : types) {
821 ensureAccess(target, c);
822 }
823 return target;
824 }
825
826 /*
827 * Ensure the given module can access the given class.
828 */
829 private static void ensureAccess(Module target, Class<?> c) {
830 Module m = c.getModule();
831 // add read edge and qualified export for the target module to access
832 if (!target.canRead(m)) {
833 Modules.addReads(target, m);
849 }
850 if (type != c) {
851 throw new IllegalArgumentException(c.getName() +
852 " referenced from a method is not visible from class loader");
853 }
854 }
855
856 private static Class<?> getElementType(Class<?> type) {
857 Class<?> e = type;
858 while (e.isArray()) {
859 e = e.getComponentType();
860 }
861 return e;
862 }
863
864 private static final ClassLoaderValue<Module> dynProxyModules =
865 new ClassLoaderValue<>();
866 private static final AtomicInteger counter = new AtomicInteger();
867
868 /*
869 * Define a dynamic module for the generated proxy classes in
870 * a non-exported package named com.sun.proxy.$MODULE.
871 *
872 * Each class loader will have one dynamic module.
873 */
874 private static Module getDynamicModule(ClassLoader loader) {
875 return dynProxyModules.computeIfAbsent(loader, (ld, clv) -> {
876 // create a dynamic module and setup module access
877 String mn = "jdk.proxy" + counter.incrementAndGet();
878 String pn = PROXY_PACKAGE_PREFIX + "." + mn;
879 ModuleDescriptor descriptor =
880 ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
881 .packages(Set.of(pn))
882 .build();
883 Module m = Modules.defineModule(ld, descriptor, null);
884 Modules.addReads(m, Proxy.class.getModule());
885 // java.base to create proxy instance
886 Modules.addExports(m, pn, Object.class.getModule());
887 return m;
888 });
889 }
890 }
|