2020import  java .nio .charset .StandardCharsets ;
2121import  java .nio .file .Files ;
2222import  java .nio .file .Path ;
23+ import  java .nio .file .Paths ;
24+ import  java .util .Arrays ;
2325import  java .util .Collections ;
2426import  java .util .Comparator ;
2527import  java .util .Map ;
2628import  java .util .Set ;
2729import  java .util .TreeMap ;
2830import  java .util .TreeSet ;
31+ import  java .util .function .Predicate ;
32+ import  java .util .stream .Collectors ;
2933import  java .util .stream .Stream ;
3034
3135import  static  org .objectweb .asm .Opcodes .ACC_DEPRECATED ;
@@ -49,15 +53,24 @@ public class JdkApiExtractor {
4953        new  AccessibleMethod ("close" , "()V" , true , false , true )
5054    );
5155
56+     private  static  String  DEPRECATIONS_ONLY  = "--deprecations-only" ;
57+     private  static  String  INCLUDE_INCUBATOR  = "--include-incubator" ;
58+ 
59+     private  static  Set <String > OPTIONAL_ARGS  = Set .of (DEPRECATIONS_ONLY , INCLUDE_INCUBATOR );
60+ 
5261    public  static  void  main (String [] args ) throws  IOException  {
5362        validateArgs (args );
54-         boolean  deprecationsOnly  = args . length  ==  2  &&  args [ 1 ]. equals ( "--deprecations-only" );
63+         boolean  deprecationsOnly  = optionalArgs ( args ). anyMatch ( DEPRECATIONS_ONLY :: equals );
5564
5665        Map <String , Set <AccessibleMethod >> accessibleImplementationsByClass  = new  TreeMap <>();
5766        Map <String , Set <AccessibleMethod >> accessibleForOverridesByClass  = new  TreeMap <>();
5867        Map <String , Set <AccessibleMethod >> deprecationsByClass  = new  TreeMap <>();
5968
60-         Utils .walkJdkModules ((moduleName , moduleClasses , moduleExports ) -> {
69+         Predicate <String > modulePredicate  = Utils .DEFAULT_MODULE_PREDICATE .or (
70+             m  -> optionalArgs (args ).anyMatch (INCLUDE_INCUBATOR ::equals ) && m .contains (".incubator." )
71+         );
72+ 
73+         Utils .walkJdkModules (modulePredicate , (moduleName , moduleClasses , moduleExports ) -> {
6174            var  visitor  = new  AccessibleClassVisitor (
6275                moduleExports ,
6376                accessibleImplementationsByClass ,
@@ -87,16 +100,37 @@ private static String internalClassName(Path clazz, String moduleName) {
87100        return  relativePath .substring (0 , relativePath .length () - ".class" .length ());
88101    }
89102
103+     private  static  Stream <String > optionalArgs (String [] args ) {
104+         return  Arrays .stream (args ).skip (1 );
105+     }
106+ 
90107    @ SuppressForbidden (reason  = "cli tool printing to standard err/out" )
91108    private  static  void  validateArgs (String [] args ) {
92-         boolean  valid  = args .length  == 1  || (args .length  == 2  && "--deprecations-only" .equals (args [1 ]));
93- 
109+         boolean  valid  = args .length  > 0  && optionalArgs (args ).allMatch (OPTIONAL_ARGS ::contains );
110+         if  (valid  && isWritableOutputPath (args [0 ]) == false ) {
111+             valid  = false ;
112+             System .err .println ("invalid output path: "  + args [0 ]);
113+         }
94114        if  (valid  == false ) {
95-             System .err .println ("usage: <output file path> [--deprecations-only]" );
115+             String  optionalArgs  = OPTIONAL_ARGS .stream ().collect (Collectors .joining ("] [" , " [" , "]" ));
116+             System .err .println ("usage: <output file path>"  + optionalArgs );
96117            System .exit (1 );
97118        }
98119    }
99120
121+     private  static  boolean  isWritableOutputPath (String  pathStr ) {
122+         try  {
123+             Path  path  = Paths .get (pathStr );
124+             if  (Files .exists (path ) && Files .isRegularFile (path )) {
125+                 return  Files .isWritable (path );
126+             }
127+             Path  parent  = path .toAbsolutePath ().getParent ();
128+             return  parent  != null  && Files .isDirectory (parent ) && Files .isWritable (parent );
129+         } catch  (Exception  e ) {
130+             return  false ;
131+         }
132+     }
133+ 
100134    @ SuppressForbidden (reason  = "cli tool printing to standard err/out" )
101135    private  static  void  writeFile (Path  path , Map <String , Set <AccessibleMethod >> methods ) throws  IOException  {
102136        System .out .println ("Writing result for "  + Runtime .version () + " to "  + path .toAbsolutePath ());
0 commit comments