@@ -495,67 +495,54 @@ private static final class ProxyBuilder {
495495 private static final ClassLoaderValue <Boolean > reverseProxyCache =
496496 new ClassLoaderValue <>();
497497
498- private static Class <?> defineProxyClass (Module m , List <Class <?>> interfaces ) {
499- String proxyPkg = null ; // package to define proxy class in
500- int accessFlags = Modifier .PUBLIC | Modifier .FINAL ;
501- boolean nonExported = false ;
498+ private record ProxyClassContext (Module module , String packageName , int accessFlags ) {
499+ private ProxyClassContext {
500+ if (module .isNamed ()) {
501+ if (packageName .isEmpty ()) {
502+ // Per JLS 7.4.2, unnamed package can only exist in unnamed modules.
503+ // This means a package-private superinterface exist in the unnamed
504+ // package of a named module.
505+ throw new InternalError ("Unnamed package cannot be added to " + module );
506+ }
502507
503- /*
504- * Record the package of a non-public proxy interface so that the
505- * proxy class will be defined in the same package. Verify that
506- * all non-public proxy interfaces are in the same package.
507- */
508- for (Class <?> intf : interfaces ) {
509- int flags = intf .getModifiers ();
510- if (!Modifier .isPublic (flags )) {
511- accessFlags = Modifier .FINAL ; // non-public, final
512- String pkg = intf .getPackageName ();
513- if (proxyPkg == null ) {
514- proxyPkg = pkg ;
515- } else if (!pkg .equals (proxyPkg )) {
516- throw new IllegalArgumentException (
517- "non-public interfaces from different packages" );
508+ if (!module .getDescriptor ().packages ().contains (packageName )) {
509+ throw new InternalError (packageName + " not exist in " + module .getName ());
510+ }
511+
512+ if (!module .isOpen (packageName , Proxy .class .getModule ())) {
513+ // Required for default method invocation
514+ throw new InternalError (packageName + " not open to " + Proxy .class .getModule ());
518515 }
519516 } else {
520- if (! intf . getModule (). isExported ( intf . getPackageName () )) {
521- // module-private types
522- nonExported = true ;
517+ if (Modifier . isPublic ( accessFlags )) {
518+ // All proxy superinterfaces are public, must be in named dynamic module
519+ throw new InternalError ( "public proxy in unnamed module: " + module ) ;
523520 }
524521 }
525- }
526522
527- if (proxyPkg == null ) {
528- // all proxy interfaces are public and exported
529- if (!m .isNamed ())
530- throw new InternalError ("unnamed module: " + m );
531- proxyPkg = nonExported ? PROXY_PACKAGE_PREFIX + "." + m .getName ()
532- : m .getName ();
533- } else if (proxyPkg .isEmpty () && m .isNamed ()) {
534- throw new IllegalArgumentException (
535- "Unnamed package cannot be added to " + m );
536- }
537-
538- if (m .isNamed ()) {
539- if (!m .getDescriptor ().packages ().contains (proxyPkg )) {
540- throw new InternalError (proxyPkg + " not exist in " + m .getName ());
523+ if ((accessFlags & ~Modifier .PUBLIC ) != 0 ) {
524+ throw new InternalError ("proxy access flags must be Modifier.PUBLIC or 0" );
541525 }
542526 }
527+ }
543528
529+ private static Class <?> defineProxyClass (ProxyClassContext context , List <Class <?>> interfaces ) {
544530 /*
545531 * Choose a name for the proxy class to generate.
546532 */
547533 long num = nextUniqueNumber .getAndIncrement ();
548- String proxyName = proxyPkg .isEmpty ()
534+ String proxyName = context . packageName () .isEmpty ()
549535 ? proxyClassNamePrefix + num
550- : proxyPkg + "." + proxyClassNamePrefix + num ;
536+ : context . packageName () + "." + proxyClassNamePrefix + num ;
551537
552- ClassLoader loader = getLoader (m );
553- trace (proxyName , m , loader , interfaces );
538+ ClassLoader loader = getLoader (context . module () );
539+ trace (proxyName , context . module () , loader , interfaces );
554540
555541 /*
556542 * Generate the specified proxy class.
557543 */
558- byte [] proxyClassFile = ProxyGenerator .generateProxyClass (loader , proxyName , interfaces , accessFlags );
544+ byte [] proxyClassFile = ProxyGenerator .generateProxyClass (loader , proxyName , interfaces ,
545+ context .accessFlags () | Modifier .FINAL );
559546 try {
560547 Class <?> pc = JLA .defineClass (loader , proxyName , proxyClassFile ,
561548 null , "__dynamic_proxy__" );
@@ -575,7 +562,7 @@ private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
575562
576563 /**
577564 * Test if given class is a class defined by
578- * {@link #defineProxyClass(Module , List)}
565+ * {@link #defineProxyClass(ProxyClassContext , List)}
579566 */
580567 static boolean isProxyClass (Class <?> c ) {
581568 return Objects .equals (reverseProxyCache .sub (c ).get (c .getClassLoader ()),
@@ -631,7 +618,7 @@ private static boolean isDebug(String flag) {
631618 // ProxyBuilder instance members start here....
632619
633620 private final List <Class <?>> interfaces ;
634- private final Module module ;
621+ private final ProxyClassContext context ;
635622 ProxyBuilder (ClassLoader loader , List <Class <?>> interfaces ) {
636623 if (!VM .isModuleSystemInited ()) {
637624 throw new InternalError ("Proxy is not supported until "
@@ -648,8 +635,8 @@ private static boolean isDebug(String flag) {
648635 validateProxyInterfaces (loader , interfaces , refTypes );
649636
650637 this .interfaces = interfaces ;
651- this .module = mapToModule (loader , interfaces , refTypes );
652- assert getLoader (module ) == loader ;
638+ this .context = proxyClassContext (loader , interfaces , refTypes );
639+ assert getLoader (context . module () ) == loader ;
653640 }
654641
655642 ProxyBuilder (ClassLoader loader , Class <?> intf ) {
@@ -667,8 +654,7 @@ private static boolean isDebug(String flag) {
667654 */
668655 @ SuppressWarnings ("removal" )
669656 Constructor <?> build () {
670- Class <?> proxyClass = defineProxyClass (module , interfaces );
671- assert !module .isNamed () || module .isOpen (proxyClass .getPackageName (), Proxy .class .getModule ());
657+ Class <?> proxyClass = defineProxyClass (context , interfaces );
672658
673659 final Constructor <?> cons ;
674660 try {
@@ -768,10 +754,11 @@ private static void addElementType(HashSet<Class<?>> types,
768754 }
769755
770756 /**
771- * Returns the module that the generated proxy class belongs to.
757+ * Returns the context for the generated proxy class, including the
758+ * module and the package it belongs to and whether it is package-private.
772759 *
773760 * If any of proxy interface is package-private, then the proxy class
774- * is in the same module of the package-private interface.
761+ * is in the same package and module as the package-private interface.
775762 *
776763 * If all proxy interfaces are public and in exported packages,
777764 * then the proxy class is in a dynamic module in an unconditionally
@@ -785,14 +772,21 @@ private static void addElementType(HashSet<Class<?>> types,
785772 *
786773 * Reads edge and qualified exports are added for dynamic module to access.
787774 */
788- private static Module mapToModule (ClassLoader loader ,
789- List <Class <?>> interfaces ,
790- Set <Class <?>> refTypes ) {
775+ private static ProxyClassContext proxyClassContext (ClassLoader loader ,
776+ List <Class <?>> interfaces ,
777+ Set <Class <?>> refTypes ) {
791778 Map <Class <?>, Module > packagePrivateTypes = new HashMap <>();
779+ boolean nonExported = false ;
780+
792781 for (Class <?> intf : interfaces ) {
793782 Module m = intf .getModule ();
794783 if (!Modifier .isPublic (intf .getModifiers ())) {
795784 packagePrivateTypes .put (intf , m );
785+ } else {
786+ if (!intf .getModule ().isExported (intf .getPackageName ())) {
787+ // module-private types
788+ nonExported = true ;
789+ }
796790 }
797791 }
798792
@@ -838,7 +832,7 @@ private static Module mapToModule(ClassLoader loader,
838832 Modules .addOpens (targetModule , targetPackageName , Proxy .class .getModule ());
839833 }
840834 // return the module of the package-private interface
841- return targetModule ;
835+ return new ProxyClassContext ( targetModule , targetPackageName , 0 ) ;
842836 }
843837
844838 // All proxy interfaces are public. So maps to a dynamic proxy module
@@ -852,7 +846,10 @@ private static Module mapToModule(ClassLoader loader,
852846 for (Class <?> c : types ) {
853847 ensureAccess (targetModule , c );
854848 }
855- return targetModule ;
849+
850+ var pkgName = nonExported ? PROXY_PACKAGE_PREFIX + '.' + targetModule .getName ()
851+ : targetModule .getName ();
852+ return new ProxyClassContext (targetModule , pkgName , Modifier .PUBLIC );
856853 }
857854
858855 /*
0 commit comments