3333import  java .util .stream .Collectors ;
3434import  java .util .stream .Stream ;
3535
36+ import  static  java .util .Collections .emptySet ;
3637import  static  org .objectweb .asm .Opcodes .ACC_DEPRECATED ;
3738import  static  org .objectweb .asm .Opcodes .ACC_FINAL ;
3839import  static  org .objectweb .asm .Opcodes .ACC_PROTECTED ;
@@ -64,9 +65,9 @@ public static void main(String[] args) throws IOException {
6465        boolean  deprecationsOnly  = optionalArgs (args ).anyMatch (DEPRECATIONS_ONLY ::equals );
6566
6667        final  Map <String , String > moduleNameByClass  = new  HashMap <>();
67-         final  Map <String , Set <AccessibleMethod >> accessibleImplementationsByClass  = new  TreeMap <>();
68-         final  Map <String , Set <AccessibleMethod >> accessibleForOverridesByClass  = new  TreeMap <>();
69-         final  Map <String , Set <AccessibleMethod >> deprecationsByClass  = new  TreeMap <>();
68+         final  Map <ModuleClass , Set <AccessibleMethod >> accessibleImplementationsByClass  = new  TreeMap <>(ModuleClass . COMPARATOR );
69+         final  Map <ModuleClass , Set <AccessibleMethod >> accessibleForOverridesByClass  = new  TreeMap <>(ModuleClass . COMPARATOR );
70+         final  Map <ModuleClass , Set <AccessibleMethod >> deprecationsByClass  = new  TreeMap <>(ModuleClass . COMPARATOR );
7071
7172        final  Map <String , Set <String >> exportsByModule  = Utils .findModuleExports ();
7273        // 1st: map class names to module names (including later excluded modules) for lookup in 2nd step 
@@ -93,7 +94,8 @@ public static void main(String[] args) throws IOException {
9394        Utils .walkJdkModules (modulePredicate , exportsByModule , (moduleName , moduleClasses , moduleExports ) -> {
9495            for  (var  classFile  : moduleClasses ) {
9596                // skip if class was already visited earlier due to a dependency on it 
96-                 if  (accessibleImplementationsByClass .containsKey (internalClassName (classFile , moduleName ))) {
97+                 String  className  = internalClassName (classFile , moduleName );
98+                 if  (accessibleImplementationsByClass .containsKey (new  ModuleClass (moduleName , className ))) {
9799                    continue ;
98100                }
99101                try  {
@@ -106,15 +108,14 @@ public static void main(String[] args) throws IOException {
106108        });
107109
108110        // finally, skip some implementations we're not interested in 
109-         Predicate <Map .Entry <String , Set <AccessibleMethod >>> predicate  = entry  -> {
110-             if  (entry .getKey ().startsWith ("com/sun/" ) && entry .getKey ().contains ("/internal/" )) {
111+         Predicate <Map .Entry <ModuleClass , Set <AccessibleMethod >>> predicate  = entry  -> {
112+             if  (entry .getKey ().clazz . startsWith ("com/sun/" ) && entry .getKey (). clazz .contains ("/internal/" )) {
111113                // skip com.sun.*.internal classes as they are not part of the supported JDK API 
112114                // even if methods override some publicly visible API 
113115                return  false ;
114116            }
115117            // skip classes that are not part of included modules, but checked due to dependencies 
116-             String  moduleName  = moduleNameByClass .get (entry .getKey ());
117-             return  modulePredicate .test (moduleName );
118+             return  modulePredicate .test (entry .getKey ().module );
118119        };
119120        writeFile (Path .of (args [0 ]), deprecationsOnly  ? deprecationsByClass  : accessibleImplementationsByClass , predicate );
120121    }
@@ -159,8 +160,8 @@ private static boolean isWritableOutputPath(String pathStr) {
159160    @ SuppressForbidden (reason  = "cli tool printing to standard err/out" )
160161    private  static  void  writeFile (
161162        Path  path ,
162-         Map <String , Set <AccessibleMethod >> methods ,
163-         Predicate <Map .Entry <String , Set <AccessibleMethod >>> predicate 
163+         Map <ModuleClass , Set <AccessibleMethod >> methods ,
164+         Predicate <Map .Entry <ModuleClass , Set <AccessibleMethod >>> predicate 
164165    ) throws  IOException  {
165166        System .out .println ("Writing result for "  + Runtime .version () + " to "  + path .toAbsolutePath ());
166167        Files .write (
@@ -170,6 +171,11 @@ private static void writeFile(
170171        );
171172    }
172173
174+     record  ModuleClass (String  module , String  clazz ) {
175+         private  static  final  Comparator <ModuleClass > COMPARATOR  = Comparator .comparing (ModuleClass ::module )
176+             .thenComparing (ModuleClass ::clazz );
177+     }
178+ 
173179    record  AccessibleMethod (String  method , String  descriptor , boolean  isPublic , boolean  isFinal , boolean  isStatic ) {
174180
175181        private  static  final  String  SEPARATOR  = "\t " ;
@@ -178,10 +184,11 @@ record AccessibleMethod(String method, String descriptor, boolean isPublic, bool
178184            .thenComparing (AccessibleMethod ::descriptor )
179185            .thenComparing (AccessibleMethod ::isStatic );
180186
181-         CharSequence  toLine (String   clazz ) {
187+         CharSequence  toLine (ModuleClass   moduleClass ) {
182188            return  String .join (
183189                SEPARATOR ,
184-                 clazz ,
190+                 moduleClass .module ,
191+                 moduleClass .clazz ,
185192                method ,
186193                descriptor ,
187194                isPublic  ? "PUBLIC"  : "PROTECTED" ,
@@ -190,23 +197,23 @@ CharSequence toLine(String clazz) {
190197            );
191198        }
192199
193-         static  Stream <CharSequence > toLines (Map .Entry <String , Set <AccessibleMethod >> entry ) {
200+         static  Stream <CharSequence > toLines (Map .Entry <ModuleClass , Set <AccessibleMethod >> entry ) {
194201            return  entry .getValue ().stream ().map (m  -> m .toLine (entry .getKey ()));
195202        }
196203    }
197204
198205    static  class  AccessibleClassVisitor  extends  ClassVisitor  {
199206        private  final  Map <String , String > moduleNameByClass ;
200207        private  final  Map <String , Set <String >> exportsByModule ;
201-         private  final  Map <String , Set <AccessibleMethod >> accessibleImplementationsByClass ;
202-         private  final  Map <String , Set <AccessibleMethod >> accessibleForOverridesByClass ;
203-         private  final  Map <String , Set <AccessibleMethod >> deprecationsByClass ;
208+         private  final  Map <ModuleClass , Set <AccessibleMethod >> accessibleImplementationsByClass ;
209+         private  final  Map <ModuleClass , Set <AccessibleMethod >> accessibleForOverridesByClass ;
210+         private  final  Map <ModuleClass , Set <AccessibleMethod >> deprecationsByClass ;
204211
205212        private  Set <AccessibleMethod > accessibleImplementations ;
206213        private  Set <AccessibleMethod > accessibleForOverrides ;
207214        private  Set <AccessibleMethod > deprecations ;
208215
209-         private  String   className ;
216+         private  ModuleClass   moduleClass ;
210217        private  boolean  isPublicClass ;
211218        private  boolean  isFinalClass ;
212219        private  boolean  isDeprecatedClass ;
@@ -215,9 +222,9 @@ static class AccessibleClassVisitor extends ClassVisitor {
215222        AccessibleClassVisitor (
216223            Map <String , String > moduleNameByClass ,
217224            Map <String , Set <String >> exportsByModule ,
218-             Map <String , Set <AccessibleMethod >> accessibleImplementationsByClass ,
219-             Map <String , Set <AccessibleMethod >> accessibleForOverridesByClass ,
220-             Map <String , Set <AccessibleMethod >> deprecationsByClass 
225+             Map <ModuleClass , Set <AccessibleMethod >> accessibleImplementationsByClass ,
226+             Map <ModuleClass , Set <AccessibleMethod >> accessibleForOverridesByClass ,
227+             Map <ModuleClass , Set <AccessibleMethod >> deprecationsByClass 
221228        ) {
222229            super (ASM9 );
223230            this .moduleNameByClass  = moduleNameByClass ;
@@ -235,23 +242,25 @@ private static Set<AccessibleMethod> newSortedSet() {
235242        public  void  visit (int  version , int  access , String  name , String  signature , String  superName , String [] interfaces ) {
236243            final  Set <AccessibleMethod > currentAccessibleForOverrides  = newSortedSet ();
237244            if  (superName  != null ) {
238-                 if  (accessibleImplementationsByClass .containsKey (superName ) == false ) {
245+                 var  superModuleClass  = getModuleClass (superName );
246+                 if  (accessibleImplementationsByClass .containsKey (superModuleClass ) == false ) {
239247                    visitSuperClass (superName );
240248                }
241-                 currentAccessibleForOverrides .addAll (accessibleForOverridesByClass .getOrDefault (superName ,  Collections . emptySet ()));
249+                 currentAccessibleForOverrides .addAll (accessibleForOverridesByClass .getOrDefault (superModuleClass ,  emptySet ()));
242250            }
243251            if  (interfaces  != null  && interfaces .length  > 0 ) {
244252                for  (var  interfaceName  : interfaces ) {
245-                     if  (accessibleImplementationsByClass .containsKey (interfaceName ) == false ) {
253+                     var  interfaceModuleClass  = getModuleClass (interfaceName );
254+                     if  (accessibleImplementationsByClass .containsKey (interfaceModuleClass ) == false ) {
246255                        visitInterface (interfaceName );
247256                    }
248-                     currentAccessibleForOverrides .addAll (accessibleForOverridesByClass .getOrDefault (interfaceName ,  Collections . emptySet ()));
257+                     currentAccessibleForOverrides .addAll (accessibleForOverridesByClass .getOrDefault (interfaceModuleClass ,  emptySet ()));
249258                }
250259            }
251260            // only initialize local state AFTER visiting all dependencies above! 
252261            super .visit (version , access , name , signature , superName , interfaces );
253-             this .isExported  = getModuleExports ( getModuleName ( name )). contains ( getPackageName ( name ) );
254-             this .className  = name ;
262+             this .moduleClass  = getModuleClass ( name );
263+             this .isExported  = getModuleExports ( moduleClass . module ). contains ( getPackageName ( name )) ;
255264            this .isPublicClass  = (access  & ACC_PUBLIC ) != 0 ;
256265            this .isFinalClass  = (access  & ACC_FINAL ) != 0 ;
257266            this .isDeprecatedClass  = (access  & ACC_DEPRECATED ) != 0 ;
@@ -260,12 +269,12 @@ public void visit(int version, int access, String name, String signature, String
260269            this .deprecations  = newSortedSet ();
261270        }
262271
263-         private  String   getModuleName (String  name ) {
272+         private  ModuleClass   getModuleClass (String  name ) {
264273            String  module  = moduleNameByClass .get (name );
265274            if  (module  == null ) {
266275                throw  new  IllegalStateException ("Unknown module for class: "  + name );
267276            }
268-             return  module ;
277+             return  new   ModuleClass ( module ,  name ) ;
269278        }
270279
271280        private  Set <String > getModuleExports (String  module ) {
@@ -279,15 +288,15 @@ private Set<String> getModuleExports(String module) {
279288        @ Override 
280289        public  void  visitEnd () {
281290            super .visitEnd ();
282-             if  (accessibleImplementationsByClass .put (className , unmodifiableSet (accessibleImplementations )) != null 
283-                 || accessibleForOverridesByClass .put (className , unmodifiableSet (accessibleForOverrides )) != null 
284-                 || deprecationsByClass .put (className , unmodifiableSet (deprecations )) != null ) {
285-                 throw  new  IllegalStateException ("Class "  + className  + " was already visited!" );
291+             if  (accessibleImplementationsByClass .put (moduleClass , unmodifiableSet (accessibleImplementations )) != null 
292+                 || accessibleForOverridesByClass .put (moduleClass , unmodifiableSet (accessibleForOverrides )) != null 
293+                 || deprecationsByClass .put (moduleClass , unmodifiableSet (deprecations )) != null ) {
294+                 throw  new  IllegalStateException ("Class "  + moduleClass . clazz  + " was already visited!" );
286295            }
287296        }
288297
289298        private  static  Set <AccessibleMethod > unmodifiableSet (Set <AccessibleMethod > set ) {
290-             return  set .isEmpty () ? Collections . emptySet () : Collections .unmodifiableSet (set );
299+             return  set .isEmpty () ? emptySet () : Collections .unmodifiableSet (set );
291300        }
292301
293302        @ SuppressForbidden (reason  = "cli tool printing to standard err/out" )
0 commit comments