< prev index next >

src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java

Print this page




  32 import java.util.HashMap;
  33 import java.util.HashSet;
  34 import java.util.Map;
  35 import java.util.Set;
  36 import java.util.TreeSet;
  37 import java.util.stream.Collectors;
  38 import java.util.stream.Stream;
  39 
  40 /**
  41  * Analyze module dependences and any reference to JDK internal APIs.
  42  * It can apply transition reduction on the resulting module graph.
  43  *
  44  * The result prints one line per module it depends on
  45  * one line per JDK internal API package it references:
  46  *     $MODULE[/$PACKAGE]
  47  *
  48  */
  49 public class ModuleExportsAnalyzer extends DepsAnalyzer {
  50     // source archive to its dependences and JDK internal APIs it references
  51     private final Map<Archive, Map<Archive,Set<String>>> deps = new HashMap<>();
  52     private final boolean showJdkInternals;

  53     private final boolean reduced;
  54     private final PrintWriter writer;
  55     private final String separator;
  56     public ModuleExportsAnalyzer(JdepsConfiguration config,
  57                                  JdepsFilter filter,
  58                                  boolean showJdkInternals,
  59                                  boolean reduced,
  60                                  PrintWriter writer,
  61                                  String separator) {
  62         super(config, filter, null,
  63               Analyzer.Type.PACKAGE,
  64               false /* all classes */);
  65         this.showJdkInternals = showJdkInternals;
  66         this.reduced = reduced;
  67         this.writer = writer;
  68         this.separator = separator;
  69     }
  70 
  71     @Override
  72     public boolean run() throws IOException {
  73         // analyze dependences
  74         boolean rc = super.run();
  75 
  76         // A visitor to record the module-level dependences as well as
  77         // use of JDK internal APIs
  78         Analyzer.Visitor visitor = (origin, originArchive, target, targetArchive) -> {
  79             Set<String> jdkInternals =
  80                 deps.computeIfAbsent(originArchive, _k -> new HashMap<>())
  81                     .computeIfAbsent(targetArchive, _k -> new HashSet<>());
  82 
  83             Module module = targetArchive.getModule();
  84             if (showJdkInternals && originArchive.getModule() != module &&
  85                     module.isJDK() && !module.isExported(target)) {
  86                 // use of JDK internal APIs
  87                 jdkInternals.add(target);





  88             }
  89         };
  90 
  91         // visit the dependences
  92         archives.stream()
  93             .filter(analyzer::hasDependences)
  94             .sorted(Comparator.comparing(Archive::getName))
  95             .forEach(archive -> analyzer.visitDependences(archive, visitor));
  96 






  97         Set<Module> modules = modules();
  98         if (showJdkInternals) {
  99             // print modules and JDK internal API dependences
 100             printDependences(modules);










 101         } else {
 102             // print module dependences
 103             writer.println(modules.stream().map(Module::name).sorted()
 104                                   .collect(Collectors.joining(separator)));
 105         }
 106         return rc;
 107     }
 108 













 109     private Set<Module> modules() {
 110         // build module graph
 111         ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration);
 112         Module root = new RootModule("root");
 113         builder.addModule(root);
 114         // find named module dependences
 115         dependenceStream()
 116             .flatMap(map -> map.keySet().stream())
 117             .filter(m -> m.getModule().isNamed()
 118                 && !configuration.rootModules().contains(m))
 119             .map(Archive::getModule)
 120             .forEach(m -> builder.addEdge(root, m));
 121 
 122         // build module dependence graph
 123         // if reduced is set, apply transition reduction
 124         Graph<Module> g = reduced ? builder.reduced() : builder.build();
 125         return g.adjacentNodes(root);
 126     }
 127 
 128     private void printDependences(Set<Module> modules) {
 129         // find use of JDK internals
 130         Map<Module, Set<String>> jdkinternals = new HashMap<>();
 131         dependenceStream()
 132             .flatMap(map -> map.entrySet().stream())
 133             .filter(e -> e.getValue().size() > 0)
 134             .forEach(e -> jdkinternals.computeIfAbsent(e.getKey().getModule(),
 135                                                        _k -> new TreeSet<>())
 136                                       .addAll(e.getValue()));
 137 
 138         // print modules and JDK internal API dependences
 139         Stream.concat(modules.stream(), jdkinternals.keySet().stream())
 140               .sorted(Comparator.comparing(Module::name))
 141               .distinct()
 142               .forEach(m -> {
 143                   if (jdkinternals.containsKey(m)) {
 144                       jdkinternals.get(m).stream()
 145                           .forEach(pn -> writer.format("   %s/%s%s", m, pn, separator));
 146                   } else {
 147                       writer.format("   %s%s", m, separator);
 148                   }
 149               });
 150     }
 151 
 152     /*
 153      * Returns a stream of dependence map from an Archive to the set of JDK
 154      * internal APIs being used.
 155      */
 156     private Stream<Map<Archive, Set<String>>> dependenceStream() {
 157         return deps.keySet().stream()
 158                    .filter(source -> !source.getModule().isNamed()
 159                             || configuration.rootModules().contains(source))
 160                    .map(deps::get);
 161     }
 162 
 163     private class RootModule extends Module {
 164         final ModuleDescriptor descriptor;
 165         RootModule(String name) {
 166             super(name);
 167 
 168             ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(name);
 169             this.descriptor = builder.build();
 170         }
 171 
 172         @Override
 173         public ModuleDescriptor descriptor() {
 174             return descriptor;
 175         }
 176     }
 177 
 178 }


  32 import java.util.HashMap;
  33 import java.util.HashSet;
  34 import java.util.Map;
  35 import java.util.Set;
  36 import java.util.TreeSet;
  37 import java.util.stream.Collectors;
  38 import java.util.stream.Stream;
  39 
  40 /**
  41  * Analyze module dependences and any reference to JDK internal APIs.
  42  * It can apply transition reduction on the resulting module graph.
  43  *
  44  * The result prints one line per module it depends on
  45  * one line per JDK internal API package it references:
  46  *     $MODULE[/$PACKAGE]
  47  *
  48  */
  49 public class ModuleExportsAnalyzer extends DepsAnalyzer {
  50     // source archive to its dependences and JDK internal APIs it references
  51     private final Map<Archive, Map<Archive,Set<String>>> deps = new HashMap<>();
  52     private final Map<String, Set<String>> missingDeps = new HashMap<>();
  53     private final boolean showInternals;
  54     private final boolean reduced;
  55     private final PrintWriter writer;
  56     private final String separator;
  57     public ModuleExportsAnalyzer(JdepsConfiguration config,
  58                                  JdepsFilter filter,
  59                                  boolean showInternals,
  60                                  boolean reduced,
  61                                  PrintWriter writer,
  62                                  String separator) {
  63         super(config, filter, null,
  64               Analyzer.Type.PACKAGE,
  65               false /* all classes */);
  66         this.showInternals = showInternals;
  67         this.reduced = reduced;
  68         this.writer = writer;
  69         this.separator = separator;
  70     }
  71 
  72     public boolean run(int maxDepth, boolean ignoreMissingDeps) throws IOException {
  73         // use compile time view so that the entire archive on classpath is analyzed
  74         boolean rc = super.run(true, maxDepth);

  75 
  76         // A visitor to record the module-level dependences as well as
  77         // use of internal APIs
  78         Analyzer.Visitor visitor = (origin, originArchive, target, targetArchive) -> {
  79             Set<String> internals =
  80                 deps.computeIfAbsent(originArchive, _k -> new HashMap<>())
  81                     .computeIfAbsent(targetArchive, _k -> new HashSet<>());
  82 
  83             Module module = targetArchive.getModule();
  84             if (showInternals && originArchive.getModule() != module &&
  85                     module.isNamed() && !module.isExported(target, module.name())) {
  86                 // use of internal APIs
  87                 internals.add(target);
  88             }
  89             if (!ignoreMissingDeps && Analyzer.notFound(targetArchive)) {
  90                 Set<String> notFound =
  91                     missingDeps.computeIfAbsent(origin, _k -> new HashSet<>());
  92                 notFound.add(target);
  93             }
  94         };
  95 
  96         // visit the dependences
  97         archives.stream()
  98             .filter(analyzer::hasDependences)
  99             .sorted(Comparator.comparing(Archive::getName))
 100             .forEach(archive -> analyzer.visitDependences(archive, visitor));
 101 
 102         // error if any missing dependence
 103         if (!rc || !missingDeps.isEmpty()) {
 104             return false;
 105         }
 106 
 107         Map<Module, Set<String>> internalPkgs = internalPackages();
 108         Set<Module> modules = modules();
 109         if (showInternals) {
 110             // print modules and JDK internal API dependences
 111             Stream.concat(modules.stream(), internalPkgs.keySet().stream())
 112                     .sorted(Comparator.comparing(Module::name))
 113                     .distinct()
 114                     .forEach(m -> {
 115                         if (internalPkgs.containsKey(m)) {
 116                             internalPkgs.get(m).stream()
 117                                 .forEach(pn -> writer.format("   %s/%s%s", m, pn, separator));
 118                         } else {
 119                             writer.format("   %s%s", m, separator);
 120                         }
 121                     });
 122         } else {
 123             // print module dependences
 124             writer.println(modules.stream().map(Module::name).sorted()
 125                                   .collect(Collectors.joining(separator)));
 126         }
 127         return rc;
 128     }
 129 
 130     /*
 131      * Prints missing dependences
 132      */
 133     void visitMissingDeps(Analyzer.Visitor visitor) {
 134         archives.stream()
 135             .filter(analyzer::hasDependences)
 136             .sorted(Comparator.comparing(Archive::getName))
 137             .filter(m -> analyzer.requires(m).anyMatch(Analyzer::notFound))
 138             .forEach(m -> {
 139                 analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE, Analyzer::notFound);
 140             });
 141     }
 142 
 143     private Set<Module> modules() {
 144         // build module graph
 145         ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration);
 146         Module root = new RootModule();
 147         builder.addModule(root);
 148         // find named module dependences
 149         dependenceStream()
 150             .flatMap(map -> map.keySet().stream())
 151             .filter(m -> m.getModule().isNamed() && !configuration.rootModules().contains(m))

 152             .map(Archive::getModule)
 153             .forEach(m -> builder.addEdge(root, m));
 154 
 155         // build module dependence graph
 156         // if reduced is set, apply transition reduction
 157         Graph<Module> g = reduced ? builder.reduced() : builder.build();
 158         return g.adjacentNodes(root);
 159     }
 160 
 161     private Map<Module, Set<String>> internalPackages() {
 162         Map<Module, Set<String>> internalPkgs = new HashMap<>();

 163         dependenceStream()
 164             .flatMap(map -> map.entrySet().stream())
 165             .filter(e -> e.getValue().size() > 0)
 166             .forEach(e -> internalPkgs.computeIfAbsent(e.getKey().getModule(),
 167                                                              _k -> new TreeSet<>())
 168                                       .addAll(e.getValue()));
 169         return internalPkgs;












 170     }
 171 
 172     /*
 173      * Returns a stream of dependence map from an Archive to the set of JDK
 174      * internal APIs being used.
 175      */
 176     private Stream<Map<Archive, Set<String>>> dependenceStream() {
 177         return deps.keySet().stream()
 178                    .filter(source -> !source.getModule().isNamed()
 179                             || configuration.rootModules().contains(source))
 180                    .map(deps::get);
 181     }
 182 
 183     /*
 184      * RootModule serves as the root node for building the module graph
 185      */
 186     private static class RootModule extends Module {
 187         static final String NAME = "root";
 188         RootModule() {
 189             super(NAME, ModuleDescriptor.newModule(NAME).build(), false);





 190         }
 191     }
 192 
 193 }
< prev index next >