24
24
import java .util .Arrays ;
25
25
import java .util .Collections ;
26
26
import java .util .Comparator ;
27
+ import java .util .HashMap ;
27
28
import java .util .Map ;
28
29
import java .util .Set ;
29
30
import java .util .TreeMap ;
@@ -62,21 +63,34 @@ public static void main(String[] args) throws IOException {
62
63
validateArgs (args );
63
64
boolean deprecationsOnly = optionalArgs (args ).anyMatch (DEPRECATIONS_ONLY ::equals );
64
65
65
- Map <String , Set <AccessibleMethod >> accessibleImplementationsByClass = new TreeMap <>();
66
- Map <String , Set <AccessibleMethod >> accessibleForOverridesByClass = new TreeMap <>();
67
- Map <String , Set <AccessibleMethod >> deprecationsByClass = new TreeMap <>();
66
+ 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
70
71
+ final Map <String , Set <String >> exportsByModule = Utils .findModuleExports ();
72
+ // 1st: map class names to module names (including later excluded modules) for lookup in 2nd step
73
+ Utils .walkJdkModules (m -> true , exportsByModule , (moduleName , moduleClasses , moduleExports ) -> {
74
+ for (var classFile : moduleClasses ) {
75
+ String prev = moduleNameByClass .put (internalClassName (classFile , moduleName ), moduleName );
76
+ if (prev != null ) {
77
+ throw new IllegalStateException ("Class " + classFile + " is in both modules " + prev + " and " + moduleName );
78
+ }
79
+ }
80
+ });
81
+
82
+ var visitor = new AccessibleClassVisitor (
83
+ moduleNameByClass ,
84
+ exportsByModule ,
85
+ accessibleImplementationsByClass ,
86
+ accessibleForOverridesByClass ,
87
+ deprecationsByClass
88
+ );
69
89
Predicate <String > modulePredicate = Utils .DEFAULT_MODULE_PREDICATE .or (
70
90
m -> optionalArgs (args ).anyMatch (INCLUDE_INCUBATOR ::equals ) && m .contains (".incubator." )
71
91
);
72
-
73
- Utils .walkJdkModules (modulePredicate , (moduleName , moduleClasses , moduleExports ) -> {
74
- var visitor = new AccessibleClassVisitor (
75
- moduleExports ,
76
- accessibleImplementationsByClass ,
77
- accessibleForOverridesByClass ,
78
- deprecationsByClass
79
- );
92
+ // 2nd: calculate accessible implementations of classes in included modules
93
+ Utils .walkJdkModules (modulePredicate , exportsByModule , (moduleName , moduleClasses , moduleExports ) -> {
80
94
for (var classFile : moduleClasses ) {
81
95
// skip if class was already visited earlier due to a dependency on it
82
96
if (accessibleImplementationsByClass .containsKey (internalClassName (classFile , moduleName ))) {
@@ -91,7 +105,18 @@ public static void main(String[] args) throws IOException {
91
105
}
92
106
});
93
107
94
- writeFile (Path .of (args [0 ]), deprecationsOnly ? deprecationsByClass : accessibleImplementationsByClass );
108
+ // 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
+ // skip com.sun.*.internal classes as they are not part of the supported JDK API
112
+ // even if methods override some publicly visible API
113
+ return false ;
114
+ }
115
+ // 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
+ };
119
+ writeFile (Path .of (args [0 ]), deprecationsOnly ? deprecationsByClass : accessibleImplementationsByClass , predicate );
95
120
}
96
121
97
122
private static String internalClassName (Path clazz , String moduleName ) {
@@ -132,9 +157,17 @@ private static boolean isWritableOutputPath(String pathStr) {
132
157
}
133
158
134
159
@ SuppressForbidden (reason = "cli tool printing to standard err/out" )
135
- private static void writeFile (Path path , Map <String , Set <AccessibleMethod >> methods ) throws IOException {
160
+ private static void writeFile (
161
+ Path path ,
162
+ Map <String , Set <AccessibleMethod >> methods ,
163
+ Predicate <Map .Entry <String , Set <AccessibleMethod >>> predicate
164
+ ) throws IOException {
136
165
System .out .println ("Writing result for " + Runtime .version () + " to " + path .toAbsolutePath ());
137
- Files .write (path , () -> methods .entrySet ().stream ().flatMap (AccessibleMethod ::toLines ).iterator (), StandardCharsets .UTF_8 );
166
+ Files .write (
167
+ path ,
168
+ () -> methods .entrySet ().stream ().filter (predicate ).flatMap (AccessibleMethod ::toLines ).iterator (),
169
+ StandardCharsets .UTF_8
170
+ );
138
171
}
139
172
140
173
record AccessibleMethod (String method , String descriptor , boolean isPublic , boolean isFinal , boolean isStatic ) {
@@ -163,7 +196,8 @@ static Stream<CharSequence> toLines(Map.Entry<String, Set<AccessibleMethod>> ent
163
196
}
164
197
165
198
static class AccessibleClassVisitor extends ClassVisitor {
166
- private final Set <String > moduleExports ;
199
+ private final Map <String , String > moduleNameByClass ;
200
+ private final Map <String , Set <String >> exportsByModule ;
167
201
private final Map <String , Set <AccessibleMethod >> accessibleImplementationsByClass ;
168
202
private final Map <String , Set <AccessibleMethod >> accessibleForOverridesByClass ;
169
203
private final Map <String , Set <AccessibleMethod >> deprecationsByClass ;
@@ -179,13 +213,15 @@ static class AccessibleClassVisitor extends ClassVisitor {
179
213
private boolean isExported ;
180
214
181
215
AccessibleClassVisitor (
182
- Set <String > moduleExports ,
216
+ Map <String , String > moduleNameByClass ,
217
+ Map <String , Set <String >> exportsByModule ,
183
218
Map <String , Set <AccessibleMethod >> accessibleImplementationsByClass ,
184
219
Map <String , Set <AccessibleMethod >> accessibleForOverridesByClass ,
185
220
Map <String , Set <AccessibleMethod >> deprecationsByClass
186
221
) {
187
222
super (ASM9 );
188
- this .moduleExports = moduleExports ;
223
+ this .moduleNameByClass = moduleNameByClass ;
224
+ this .exportsByModule = exportsByModule ;
189
225
this .accessibleImplementationsByClass = accessibleImplementationsByClass ;
190
226
this .accessibleForOverridesByClass = accessibleForOverridesByClass ;
191
227
this .deprecationsByClass = deprecationsByClass ;
@@ -214,7 +250,7 @@ public void visit(int version, int access, String name, String signature, String
214
250
}
215
251
// only initialize local state AFTER visiting all dependencies above!
216
252
super .visit (version , access , name , signature , superName , interfaces );
217
- this .isExported = moduleExports .contains (getPackageName (name ));
253
+ this .isExported = getModuleExports ( getModuleName ( name )) .contains (getPackageName (name ));
218
254
this .className = name ;
219
255
this .isPublicClass = (access & ACC_PUBLIC ) != 0 ;
220
256
this .isFinalClass = (access & ACC_FINAL ) != 0 ;
@@ -224,6 +260,22 @@ public void visit(int version, int access, String name, String signature, String
224
260
this .deprecations = newSortedSet ();
225
261
}
226
262
263
+ private String getModuleName (String name ) {
264
+ String module = moduleNameByClass .get (name );
265
+ if (module == null ) {
266
+ throw new IllegalStateException ("Unknown module for class: " + name );
267
+ }
268
+ return module ;
269
+ }
270
+
271
+ private Set <String > getModuleExports (String module ) {
272
+ Set <String > exports = exportsByModule .get (module );
273
+ if (exports == null ) {
274
+ throw new IllegalStateException ("Unknown exports for module: " + module );
275
+ }
276
+ return exports ;
277
+ }
278
+
227
279
@ Override
228
280
public void visitEnd () {
229
281
super .visitEnd ();
0 commit comments