33
33
import java .util .stream .Collectors ;
34
34
import java .util .stream .Stream ;
35
35
36
+ import static java .util .Collections .emptySet ;
36
37
import static org .objectweb .asm .Opcodes .ACC_DEPRECATED ;
37
38
import static org .objectweb .asm .Opcodes .ACC_FINAL ;
38
39
import static org .objectweb .asm .Opcodes .ACC_PROTECTED ;
@@ -64,9 +65,9 @@ public static void main(String[] args) throws IOException {
64
65
boolean deprecationsOnly = optionalArgs (args ).anyMatch (DEPRECATIONS_ONLY ::equals );
65
66
66
67
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 );
70
71
71
72
final Map <String , Set <String >> exportsByModule = Utils .findModuleExports ();
72
73
// 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 {
93
94
Utils .walkJdkModules (modulePredicate , exportsByModule , (moduleName , moduleClasses , moduleExports ) -> {
94
95
for (var classFile : moduleClasses ) {
95
96
// 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 ))) {
97
99
continue ;
98
100
}
99
101
try {
@@ -106,15 +108,14 @@ public static void main(String[] args) throws IOException {
106
108
});
107
109
108
110
// 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/" )) {
111
113
// skip com.sun.*.internal classes as they are not part of the supported JDK API
112
114
// even if methods override some publicly visible API
113
115
return false ;
114
116
}
115
117
// 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 );
118
119
};
119
120
writeFile (Path .of (args [0 ]), deprecationsOnly ? deprecationsByClass : accessibleImplementationsByClass , predicate );
120
121
}
@@ -159,8 +160,8 @@ private static boolean isWritableOutputPath(String pathStr) {
159
160
@ SuppressForbidden (reason = "cli tool printing to standard err/out" )
160
161
private static void writeFile (
161
162
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
164
165
) throws IOException {
165
166
System .out .println ("Writing result for " + Runtime .version () + " to " + path .toAbsolutePath ());
166
167
Files .write (
@@ -170,6 +171,11 @@ private static void writeFile(
170
171
);
171
172
}
172
173
174
+ record ModuleClass (String module , String clazz ) {
175
+ private static final Comparator <ModuleClass > COMPARATOR = Comparator .comparing (ModuleClass ::module )
176
+ .thenComparing (ModuleClass ::clazz );
177
+ }
178
+
173
179
record AccessibleMethod (String method , String descriptor , boolean isPublic , boolean isFinal , boolean isStatic ) {
174
180
175
181
private static final String SEPARATOR = "\t " ;
@@ -178,10 +184,11 @@ record AccessibleMethod(String method, String descriptor, boolean isPublic, bool
178
184
.thenComparing (AccessibleMethod ::descriptor )
179
185
.thenComparing (AccessibleMethod ::isStatic );
180
186
181
- CharSequence toLine (String clazz ) {
187
+ CharSequence toLine (ModuleClass moduleClass ) {
182
188
return String .join (
183
189
SEPARATOR ,
184
- clazz ,
190
+ moduleClass .module ,
191
+ moduleClass .clazz ,
185
192
method ,
186
193
descriptor ,
187
194
isPublic ? "PUBLIC" : "PROTECTED" ,
@@ -190,23 +197,23 @@ CharSequence toLine(String clazz) {
190
197
);
191
198
}
192
199
193
- static Stream <CharSequence > toLines (Map .Entry <String , Set <AccessibleMethod >> entry ) {
200
+ static Stream <CharSequence > toLines (Map .Entry <ModuleClass , Set <AccessibleMethod >> entry ) {
194
201
return entry .getValue ().stream ().map (m -> m .toLine (entry .getKey ()));
195
202
}
196
203
}
197
204
198
205
static class AccessibleClassVisitor extends ClassVisitor {
199
206
private final Map <String , String > moduleNameByClass ;
200
207
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 ;
204
211
205
212
private Set <AccessibleMethod > accessibleImplementations ;
206
213
private Set <AccessibleMethod > accessibleForOverrides ;
207
214
private Set <AccessibleMethod > deprecations ;
208
215
209
- private String className ;
216
+ private ModuleClass moduleClass ;
210
217
private boolean isPublicClass ;
211
218
private boolean isFinalClass ;
212
219
private boolean isDeprecatedClass ;
@@ -215,9 +222,9 @@ static class AccessibleClassVisitor extends ClassVisitor {
215
222
AccessibleClassVisitor (
216
223
Map <String , String > moduleNameByClass ,
217
224
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
221
228
) {
222
229
super (ASM9 );
223
230
this .moduleNameByClass = moduleNameByClass ;
@@ -235,23 +242,25 @@ private static Set<AccessibleMethod> newSortedSet() {
235
242
public void visit (int version , int access , String name , String signature , String superName , String [] interfaces ) {
236
243
final Set <AccessibleMethod > currentAccessibleForOverrides = newSortedSet ();
237
244
if (superName != null ) {
238
- if (accessibleImplementationsByClass .containsKey (superName ) == false ) {
245
+ var superModuleClass = getModuleClass (superName );
246
+ if (accessibleImplementationsByClass .containsKey (superModuleClass ) == false ) {
239
247
visitSuperClass (superName );
240
248
}
241
- currentAccessibleForOverrides .addAll (accessibleForOverridesByClass .getOrDefault (superName , Collections . emptySet ()));
249
+ currentAccessibleForOverrides .addAll (accessibleForOverridesByClass .getOrDefault (superModuleClass , emptySet ()));
242
250
}
243
251
if (interfaces != null && interfaces .length > 0 ) {
244
252
for (var interfaceName : interfaces ) {
245
- if (accessibleImplementationsByClass .containsKey (interfaceName ) == false ) {
253
+ var interfaceModuleClass = getModuleClass (interfaceName );
254
+ if (accessibleImplementationsByClass .containsKey (interfaceModuleClass ) == false ) {
246
255
visitInterface (interfaceName );
247
256
}
248
- currentAccessibleForOverrides .addAll (accessibleForOverridesByClass .getOrDefault (interfaceName , Collections . emptySet ()));
257
+ currentAccessibleForOverrides .addAll (accessibleForOverridesByClass .getOrDefault (interfaceModuleClass , emptySet ()));
249
258
}
250
259
}
251
260
// only initialize local state AFTER visiting all dependencies above!
252
261
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 )) ;
255
264
this .isPublicClass = (access & ACC_PUBLIC ) != 0 ;
256
265
this .isFinalClass = (access & ACC_FINAL ) != 0 ;
257
266
this .isDeprecatedClass = (access & ACC_DEPRECATED ) != 0 ;
@@ -260,12 +269,12 @@ public void visit(int version, int access, String name, String signature, String
260
269
this .deprecations = newSortedSet ();
261
270
}
262
271
263
- private String getModuleName (String name ) {
272
+ private ModuleClass getModuleClass (String name ) {
264
273
String module = moduleNameByClass .get (name );
265
274
if (module == null ) {
266
275
throw new IllegalStateException ("Unknown module for class: " + name );
267
276
}
268
- return module ;
277
+ return new ModuleClass ( module , name ) ;
269
278
}
270
279
271
280
private Set <String > getModuleExports (String module ) {
@@ -279,15 +288,15 @@ private Set<String> getModuleExports(String module) {
279
288
@ Override
280
289
public void visitEnd () {
281
290
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!" );
286
295
}
287
296
}
288
297
289
298
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 );
291
300
}
292
301
293
302
@ SuppressForbidden (reason = "cli tool printing to standard err/out" )
0 commit comments