8167057: jdeps option to list modules and internal APIs for @modules for test dev
Reviewed-by: dfuchs
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java Fri Oct 28 10:17:56 2016 +0100
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java Mon Oct 31 18:06:03 2016 -0700
@@ -50,7 +50,7 @@
*
* Type of filters:
* source filter: -include <pattern>
- * target filter: -package, -regex, -requires
+ * target filter: -package, -regex, --require
*
* The initial archive set for analysis includes
* 1. archives specified in the command line arguments
@@ -146,7 +146,9 @@
// analyze the dependencies collected
analyzer.run(archives, finder.locationToArchive());
- writer.generateOutput(archives, analyzer);
+ if (writer != null) {
+ writer.generateOutput(archives, analyzer);
+ }
} finally {
finder.shutdown();
}
@@ -156,7 +158,7 @@
/**
* Returns the archives for reporting that has matching dependences.
*
- * If -requires is set, they should be excluded.
+ * If --require is set, they should be excluded.
*/
Set<Archive> archives() {
if (filter.requiresFilter().isEmpty()) {
@@ -165,7 +167,7 @@
.filter(Archive::hasDependences)
.collect(Collectors.toSet());
} else {
- // use the archives that have dependences and not specified in -requires
+ // use the archives that have dependences and not specified in --require
return archives.stream()
.filter(filter::include)
.filter(source -> !filter.requiresFilter().contains(source))
@@ -360,16 +362,17 @@
Archive source = dep.originArchive();
Archive target = dep.targetArchive();
String pn = dep.target();
- if ((verbose == CLASS || verbose == VERBOSE)) {
+ if (verbose == CLASS || verbose == VERBOSE) {
int i = dep.target().lastIndexOf('.');
pn = i > 0 ? dep.target().substring(0, i) : "";
}
final Info info;
+ Module targetModule = target.getModule();
if (source == target) {
info = Info.MODULE_PRIVATE;
- } else if (!target.getModule().isNamed()) {
+ } else if (!targetModule.isNamed()) {
info = Info.EXPORTED_API;
- } else if (target.getModule().isExported(pn)) {
+ } else if (targetModule.isExported(pn) && !targetModule.isJDKUnsupported()) {
info = Info.EXPORTED_API;
} else {
Module module = target.getModule();
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java Fri Oct 28 10:17:56 2016 +0100
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java Mon Oct 31 18:06:03 2016 -0700
@@ -41,7 +41,7 @@
* 2. -filter:package to filter out same-package dependencies
* This filter is applied when jdeps parses the class files
* and filtered dependencies are not stored in the Analyzer.
- * 3. -requires specifies to match target dependence from the given module
+ * 3. --require specifies to match target dependence from the given module
* This gets expanded into package lists to be filtered.
* 4. -filter:archive to filter out same-archive dependencies
* This filter is applied later in the Analyzer as the
@@ -166,7 +166,7 @@
// accepts target that is JDK class but not exported
Module module = targetArchive.getModule();
return originArchive != targetArchive &&
- module.isJDK() && !module.isExported(target.getPackageName());
+ isJDKInternalPackage(module, target.getPackageName());
} else if (filterSameArchive) {
// accepts origin and target that from different archive
return originArchive != targetArchive;
@@ -174,6 +174,18 @@
return true;
}
+ /**
+ * Tests if the package is an internal package of the given module.
+ */
+ public boolean isJDKInternalPackage(Module module, String pn) {
+ if (module.isJDKUnsupported()) {
+ // its exported APIs are unsupported
+ return true;
+ }
+
+ return module.isJDK() && !module.isExported(pn);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Fri Oct 28 10:17:56 2016 +0100
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Mon Oct 31 18:06:03 2016 -0700
@@ -221,6 +221,12 @@
}
}
},
+ new Option(false, "--list-deps", "--list-reduced-deps") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.showModulesAddExports = true;
+ task.options.reduced = opt.equals("--list-reduced-deps");
+ }
+ },
// ---- paths option ----
new Option(true, "-cp", "-classpath", "--class-path") {
@@ -517,13 +523,13 @@
.forEach(e -> System.out.format("split package: %s %s%n", e.getKey(),
e.getValue().toString()));
- // check if any module specified in -requires is missing
+ // check if any module specified in --require is missing
Stream.concat(options.addmods.stream(), options.requires.stream())
.filter(mn -> !config.isValidToken(mn))
.forEach(mn -> config.findModule(mn).orElseThrow(() ->
new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
- // --gen-module-info
+ // --generate-module-info
if (options.genModuleInfo != null) {
return genModuleInfo(config);
}
@@ -533,6 +539,13 @@
return new ModuleAnalyzer(config, log, options.checkModuleDeps).run();
}
+ if (options.showModulesAddExports) {
+ return new ModuleExportsAnalyzer(config,
+ dependencyFilter(config),
+ options.reduced,
+ log).run();
+ }
+
if (options.dotOutputDir != null &&
(options.verbose == SUMMARY || options.verbose == MODULE) &&
!options.addmods.isEmpty() && inputArgs.isEmpty()) {
@@ -555,7 +568,7 @@
.appModulePath(options.modulePath)
.addmods(options.addmods);
- if (options.checkModuleDeps != null) {
+ if (options.checkModuleDeps != null || options.showModulesAddExports) {
// check all system modules in the image
builder.allModules();
}
@@ -597,10 +610,10 @@
// analyze the dependencies
DepsAnalyzer analyzer = new DepsAnalyzer(config,
- dependencyFilter(config),
- writer,
- options.verbose,
- options.apiOnly);
+ dependencyFilter(config),
+ writer,
+ options.verbose,
+ options.apiOnly);
boolean ok = analyzer.run(options.compileTimeView, options.depth);
@@ -727,7 +740,7 @@
* Returns a filter used during dependency analysis
*/
private JdepsFilter dependencyFilter(JdepsConfiguration config) {
- // Filter specified by -filter, -package, -regex, and -requires options
+ // Filter specified by -filter, -package, -regex, and --require options
JdepsFilter.Builder builder = new JdepsFilter.Builder();
// source filters
@@ -737,7 +750,7 @@
builder.filter(options.filterSamePackage, options.filterSameArchive);
builder.findJDKInternals(options.findJDKInternals);
- // -requires
+ // --require
if (!options.requires.isEmpty()) {
options.requires.stream()
.forEach(mn -> {
@@ -757,8 +770,8 @@
// check if system module is set
config.rootModules().stream()
- .map(Module::name)
- .forEach(builder::includeIfSystemModule);
+ .map(Module::name)
+ .forEach(builder::includeIfSystemModule);
return builder.build();
}
@@ -886,6 +899,8 @@
String rootModule;
Set<String> addmods = new HashSet<>();
Runtime.Version multiRelease;
+ boolean showModulesAddExports;
+ boolean reduced;
boolean hasFilter() {
return numFilters() > 0;
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java Fri Oct 28 10:17:56 2016 +0100
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java Mon Oct 31 18:06:03 2016 -0700
@@ -50,7 +50,7 @@
final boolean showProfile;
final boolean showModule;
- private JdepsWriter(Analyzer.Type type, boolean showProfile, boolean showModule) {
+ JdepsWriter(Analyzer.Type type, boolean showProfile, boolean showModule) {
this.type = type;
this.showProfile = showProfile;
this.showModule = showModule;
@@ -318,8 +318,7 @@
}
// exported API
- boolean jdkunsupported = Module.JDK_UNSUPPORTED.equals(module.name());
- if (module.isExported(pn) && !jdkunsupported) {
+ if (module.isExported(pn) && !module.isJDKUnsupported()) {
return showProfileOrModule(module);
}
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java Fri Oct 28 10:17:56 2016 +0100
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java Mon Oct 31 18:06:03 2016 -0700
@@ -126,12 +126,13 @@
* Tests if the package of the given name is exported.
*/
public boolean isExported(String pn) {
- if (JDK_UNSUPPORTED.equals(this.name())) {
- return false;
- }
return exports.containsKey(pn) ? exports.get(pn).isEmpty() : false;
}
+ public boolean isJDKUnsupported() {
+ return JDK_UNSUPPORTED.equals(this.name());
+ }
+
/**
* Converts this module to a strict module with the given dependences
*
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java Fri Oct 28 10:17:56 2016 +0100
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java Mon Oct 31 18:06:03 2016 -0700
@@ -41,10 +41,8 @@
import java.nio.file.Path;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -179,50 +177,43 @@
return builder.build();
}
- ModuleDescriptor reduced() {
- Graph.Builder<Module> bd = new Graph.Builder<>();
+ private Graph<Module> buildReducedGraph() {
+ ModuleGraphBuilder rpBuilder = new ModuleGraphBuilder(configuration);
+ rpBuilder.addModule(root);
requiresPublic.stream()
- .forEach(m -> {
- bd.addNode(m);
- bd.addEdge(root, m);
- });
+ .forEach(m -> rpBuilder.addEdge(root, m));
// requires public graph
- Graph<Module> rbg = bd.build().reduce();
+ Graph<Module> rbg = rpBuilder.build().reduce();
+
+ ModuleGraphBuilder gb = new ModuleGraphBuilder(configuration);
+ gb.addModule(root);
+ requires.stream()
+ .forEach(m -> gb.addEdge(root, m));
// transitive reduction
- Graph<Module> newGraph = buildGraph(requires).reduce(rbg);
+ Graph<Module> newGraph = gb.buildGraph().reduce(rbg);
if (DEBUG) {
System.err.println("after transitive reduction: ");
newGraph.printGraph(log);
}
-
- return descriptor(requiresPublic, newGraph.adjacentNodes(root));
+ return newGraph;
}
+ /**
+ * Apply the transitive reduction on the module graph
+ * and returns the corresponding ModuleDescriptor
+ */
+ ModuleDescriptor reduced() {
+ Graph<Module> g = buildReducedGraph();
+ return descriptor(requiresPublic, g.adjacentNodes(root));
+ }
/**
* Apply transitive reduction on the resulting graph and reports
* recommended requires.
*/
private void analyzeDeps() {
- Graph.Builder<Module> builder = new Graph.Builder<>();
- requiresPublic.stream()
- .forEach(m -> {
- builder.addNode(m);
- builder.addEdge(root, m);
- });
-
- // requires public graph
- Graph<Module> rbg = buildGraph(requiresPublic).reduce();
-
- // transitive reduction
- Graph<Module> newGraph = buildGraph(requires).reduce(builder.build().reduce());
- if (DEBUG) {
- System.err.println("after transitive reduction: ");
- newGraph.printGraph(log);
- }
-
printModuleDescriptor(log, root);
ModuleDescriptor analyzedDescriptor = descriptor();
@@ -277,45 +268,6 @@
/**
- * Returns a graph of modules required by the specified module.
- *
- * Requires public edges of the dependences are added to the graph.
- */
- private Graph<Module> buildGraph(Set<Module> deps) {
- Graph.Builder<Module> builder = new Graph.Builder<>();
- builder.addNode(root);
- Set<Module> visited = new HashSet<>();
- visited.add(root);
- Deque<Module> deque = new LinkedList<>();
- deps.stream()
- .forEach(m -> {
- deque.add(m);
- builder.addEdge(root, m);
- });
-
- // read requires public from ModuleDescription
- Module source;
- while ((source = deque.poll()) != null) {
- if (visited.contains(source))
- continue;
-
- visited.add(source);
- builder.addNode(source);
- Module from = source;
- source.descriptor().requires().stream()
- .filter(req -> req.modifiers().contains(PUBLIC))
- .map(ModuleDescriptor.Requires::name)
- .map(configuration::findModule)
- .flatMap(Optional::stream)
- .forEach(m -> {
- deque.add(m);
- builder.addEdge(from, m);
- });
- }
- return builder.build();
- }
-
- /**
* Detects any qualified exports not used by the target module.
*/
private Map<String, Set<String>> unusedQualifiedExports() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java Mon Oct 31 18:06:03 2016 -0700
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.jdeps;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.module.ModuleDescriptor;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static com.sun.tools.jdeps.Analyzer.NOT_FOUND;
+
+/**
+ * Analyze module dependences and any reference to JDK internal APIs.
+ * It can apply transition reduction on the resulting module graph.
+ *
+ * The result prints one line per module it depends on
+ * one line per JDK internal API package it references:
+ * $MODULE[/$PACKAGE]
+ *
+ */
+public class ModuleExportsAnalyzer extends DepsAnalyzer {
+ // source archive to its dependences and JDK internal APIs it references
+ private final Map<Archive, Map<Archive,Set<String>>> deps = new HashMap<>();
+ private final boolean reduced;
+ private final PrintWriter writer;
+ public ModuleExportsAnalyzer(JdepsConfiguration config,
+ JdepsFilter filter,
+ boolean reduced,
+ PrintWriter writer) {
+ super(config, filter, null,
+ Analyzer.Type.PACKAGE,
+ false /* all classes */);
+ this.reduced = reduced;
+ this.writer = writer;
+ }
+
+ @Override
+ public boolean run() throws IOException {
+ // analyze dependences
+ boolean rc = super.run();
+
+ // A visitor to record the module-level dependences as well as
+ // use of JDK internal APIs
+ Analyzer.Visitor visitor = new Analyzer.Visitor() {
+ @Override
+ public void visitDependence(String origin, Archive originArchive,
+ String target, Archive targetArchive)
+ {
+ Set<String> jdkInternals =
+ deps.computeIfAbsent(originArchive, _k -> new HashMap<>())
+ .computeIfAbsent(targetArchive, _k -> new HashSet<>());
+
+ Module module = targetArchive.getModule();
+ if (originArchive.getModule() != module &&
+ module.isJDK() && !module.isExported(target)) {
+ // use of JDK internal APIs
+ jdkInternals.add(target);
+ }
+ }
+ };
+
+ // visit the dependences
+ archives.stream()
+ .filter(analyzer::hasDependences)
+ .sorted(Comparator.comparing(Archive::getName))
+ .forEach(archive -> analyzer.visitDependences(archive, visitor));
+
+
+ // print the dependences on named modules
+ printDependences();
+
+ // print the dependences on unnamed module
+ deps.values().stream()
+ .flatMap(map -> map.keySet().stream())
+ .filter(archive -> !archive.getModule().isNamed())
+ .map(archive -> archive != NOT_FOUND
+ ? "unnamed module: " + archive.getPathName()
+ : archive.getPathName())
+ .distinct()
+ .sorted()
+ .forEach(archive -> writer.format(" %s%n", archive));
+
+ return rc;
+ }
+
+ private void printDependences() {
+ // find use of JDK internals
+ Map<Module, Set<String>> jdkinternals = new HashMap<>();
+ deps.keySet().stream()
+ .filter(source -> !source.getModule().isNamed())
+ .map(deps::get)
+ .flatMap(map -> map.entrySet().stream())
+ .filter(e -> e.getValue().size() > 0)
+ .forEach(e -> jdkinternals.computeIfAbsent(e.getKey().getModule(),
+ _k -> new HashSet<>())
+ .addAll(e.getValue()));
+
+
+ // build module graph
+ ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration);
+ Module root = new RootModule("root");
+ builder.addModule(root);
+ // find named module dependences
+ deps.keySet().stream()
+ .filter(source -> !source.getModule().isNamed())
+ .map(deps::get)
+ .flatMap(map -> map.keySet().stream())
+ .filter(m -> m.getModule().isNamed())
+ .map(Archive::getModule)
+ .forEach(m -> builder.addEdge(root, m));
+
+ // module dependences
+ Set<Module> modules = builder.build().adjacentNodes(root);
+
+ // if reduced is set, apply transition reduction
+ Set<Module> reducedSet = reduced ? builder.reduced().adjacentNodes(root)
+ : modules;
+
+ modules.stream()
+ .sorted(Comparator.comparing(Module::name))
+ .forEach(m -> {
+ if (jdkinternals.containsKey(m)) {
+ jdkinternals.get(m).stream()
+ .sorted()
+ .forEach(pn -> writer.format(" %s/%s%n", m, pn));
+ } else if (reducedSet.contains(m)){
+ // if the transition reduction is applied, show the reduced graph
+ writer.format(" %s%n", m);
+ }
+ });
+ }
+
+
+ private class RootModule extends Module {
+ final ModuleDescriptor descriptor;
+ RootModule(String name) {
+ super(name);
+
+ ModuleDescriptor.Builder builder = new ModuleDescriptor.Builder(name);
+ this.descriptor = builder.build();
+ }
+
+ @Override
+ public ModuleDescriptor descriptor() {
+ return descriptor;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleGraphBuilder.java Mon Oct 31 18:06:03 2016 -0700
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.jdeps;
+
+import java.io.PrintWriter;
+import java.lang.module.ModuleDescriptor;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
+import static com.sun.tools.jdeps.Module.*;
+
+/**
+ * A builder to create a Graph<Module>
+ */
+public class ModuleGraphBuilder extends Graph.Builder<Module> {
+ final JdepsConfiguration config;
+
+ ModuleGraphBuilder(JdepsConfiguration config) {
+ this.config = config;
+ }
+
+ /**
+ * Adds a module to the graph.
+ */
+ ModuleGraphBuilder addModule(Module module) {
+ addNode(module);
+ return this;
+ }
+
+ /**
+ * Apply transitive reduction on the resulting graph
+ */
+ public Graph<Module> reduced() {
+ Graph<Module> graph = build();
+ // transitive reduction
+ Graph<Module> newGraph = buildGraph(graph.edges()).reduce();
+
+ if (DEBUG) {
+ PrintWriter log = new PrintWriter(System.err);
+ System.err.println("before transitive reduction: ");
+ graph.printGraph(log);
+ System.err.println("after transitive reduction: ");
+ newGraph.printGraph(log);
+ }
+
+ return newGraph;
+ }
+
+ public Graph<Module> buildGraph() {
+ Graph<Module> graph = build();
+ return buildGraph(graph.edges());
+ }
+
+ /**
+ * Build a graph of module from the given dependences.
+ *
+ * It transitively includes all implied read edges.
+ */
+ private Graph<Module> buildGraph(Map<Module, Set<Module>> edges) {
+ Graph.Builder<Module> builder = new Graph.Builder<>();
+ Set<Module> visited = new HashSet<>();
+ Deque<Module> deque = new LinkedList<>();
+ edges.entrySet().stream().forEach(e -> {
+ Module m = e.getKey();
+ deque.add(m);
+ e.getValue().stream().forEach(v -> {
+ deque.add(v);
+ builder.addEdge(m, v);
+ });
+ });
+
+ // read requires public from ModuleDescriptor
+ Module source;
+ while ((source = deque.poll()) != null) {
+ if (visited.contains(source))
+ continue;
+
+ visited.add(source);
+ builder.addNode(source);
+ Module from = source;
+ requiresPublic(from).forEach(m -> {
+ deque.add(m);
+ builder.addEdge(from, m);
+ });
+ }
+ return builder.build();
+ }
+
+ /*
+ * Returns a stream of modules upon which the given module `requires public`
+ */
+ public Stream<Module> requiresPublic(Module m) {
+ // find requires public
+ return m.descriptor()
+ .requires().stream()
+ .filter(req -> req.modifiers().contains(PUBLIC))
+ .map(ModuleDescriptor.Requires::name)
+ .map(config::findModule)
+ .flatMap(Optional::stream);
+ }
+}
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Fri Oct 28 10:17:56 2016 +0100
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Mon Oct 31 18:06:03 2016 -0700
@@ -149,6 +149,15 @@
\ used with -p, -e and -s options.\n\
\ WARNING: JDK internal APIs are inaccessible.
+main.opt.list-deps=\
+\ --list-deps Lists the dependences and use of JDK internal\n\
+\ APIs.\n\
+\ --list-reduced-deps Same as --list-deps with not listing\n\
+\ the implied reads edges from the module graph\n\
+\ If module M1 depends on M2 and M3,\n\
+\ M2 requires public on M3, then M1 reading M3 is\n\
+\ implied and removed from the module graph.
+
main.opt.depth=\
\ -depth=<depth> Specify the depth of the transitive\n\
\ dependency analysis
--- a/langtools/test/tools/jdeps/lib/JdepsRunner.java Fri Oct 28 10:17:56 2016 +0100
+++ b/langtools/test/tools/jdeps/lib/JdepsRunner.java Mon Oct 31 18:06:03 2016 -0700
@@ -27,16 +27,19 @@
import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;
+import java.util.spi.ToolProvider;
import java.util.stream.Collectors;
/**
* JdepsRunner class to invoke jdeps with the given command line argument
*/
public class JdepsRunner {
+ private static final ToolProvider JDEPS_TOOL = ToolProvider.findFirst("jdeps")
+ .orElseThrow(() -> new RuntimeException("jdeps tool not found"));
+
public static JdepsRunner run(String... args) {
JdepsRunner jdeps = new JdepsRunner(args);
- int rc = jdeps.run();
- jdeps.printStdout(System.err);
+ int rc = jdeps.run(true);
if (rc != 0)
throw new Error("jdeps failed: rc=" + rc);
return jdeps;
@@ -46,7 +49,7 @@
final StringWriter stderr = new StringWriter();
final String[] args;
public JdepsRunner(String... args) {
- System.err.println("jdeps " + Arrays.stream(args)
+ System.out.println("jdeps " + Arrays.stream(args)
.collect(Collectors.joining(" ")));
this.args = args;
}
@@ -60,10 +63,12 @@
}
public int run(boolean showOutput) {
- try (PrintWriter pw = new PrintWriter(stdout)) {
- int rc = com.sun.tools.jdeps.Main.run(args, pw);
+ try (PrintWriter pwout = new PrintWriter(stdout);
+ PrintWriter pwerr = new PrintWriter(stderr)) {
+ int rc = JDEPS_TOOL.run(pwout, pwerr, args);
if (showOutput) {
- System.err.println(stdout.toString());
+ printStdout(System.out);
+ printStderr(System.out);
}
return rc;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/listdeps/ListModuleDeps.java Mon Oct 31 18:06:03 2016 -0700
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8167057
+ * @summary Tests split packages
+ * @modules java.logging
+ * java.xml
+ * jdk.compiler
+ * jdk.jdeps
+ * jdk.unsupported
+ * @library ../lib
+ * @build CompilerUtils JdepsRunner
+ * @run testng ListModuleDeps
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class ListModuleDeps {
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path CLASSES_DIR = Paths.get("classes");
+ private static final Path LIB_DIR = Paths.get("lib");
+
+ private static final Path FOO_CLASS =
+ CLASSES_DIR.resolve("z").resolve("Foo.class");
+ private static final Path BAR_CLASS =
+ CLASSES_DIR.resolve("z").resolve("Bar.class");
+ private static final Path UNSAFE_CLASS =
+ CLASSES_DIR.resolve("z").resolve("UseUnsafe.class");
+
+ /**
+ * Compiles classes used by the test
+ */
+ @BeforeTest
+ public void compileAll() throws Exception {
+ // compile library
+ assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "lib"), LIB_DIR));
+
+ // compile classes in unnamed module
+ assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "z"),
+ CLASSES_DIR,
+ "-cp", LIB_DIR.toString(),
+ "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
+ "--add-exports=java.base/sun.security.util=ALL-UNNAMED",
+ "--add-exports=java.xml/jdk.xml.internal=ALL-UNNAMED"
+ ));
+ }
+
+ @Test(dataProvider = "listdeps")
+ public void testListDeps(Path classes, String[] expected) {
+ JdepsRunner jdeps = JdepsRunner.run(
+ "--class-path", LIB_DIR.toString(),
+ "--list-deps", classes.toString()
+ );
+ String[] output = Arrays.stream(jdeps.output())
+ .map(s -> s.trim())
+ .toArray(String[]::new);
+ assertEquals(output, expected);
+ }
+
+ @Test(dataProvider = "reduceddeps")
+ public void testListReducedDeps(Path classes, String[] expected) {
+ JdepsRunner jdeps = JdepsRunner.run(
+ "--class-path", LIB_DIR.toString(),
+ "--list-reduced-deps", classes.toString()
+ );
+ String[] output = Arrays.stream(jdeps.output())
+ .map(s -> s.trim())
+ .toArray(String[]::new);
+ assertEquals(output, expected);
+ }
+
+
+ @DataProvider(name = "listdeps")
+ public Object[][] listdeps() {
+ return new Object[][] {
+ { CLASSES_DIR, new String[] {
+ "java.base/jdk.internal.misc",
+ "java.base/sun.security.util",
+ "java.logging",
+ "java.sql",
+ "java.xml/jdk.xml.internal",
+ "jdk.unsupported",
+ "unnamed module: lib"
+ }
+ },
+
+ { FOO_CLASS, new String[] {
+ "java.base",
+ "java.logging",
+ "java.sql",
+ "java.xml",
+ "unnamed module: lib"
+ }
+ },
+
+ { BAR_CLASS, new String[] {
+ "java.base/sun.security.util",
+ "java.xml/jdk.xml.internal",
+ }
+ },
+
+ { UNSAFE_CLASS, new String[] {
+ "java.base/jdk.internal.misc",
+ "jdk.unsupported",
+ }
+ },
+ };
+ }
+
+ @DataProvider(name = "reduceddeps")
+ public Object[][] reduceddeps() {
+ Path barClass = CLASSES_DIR.resolve("z").resolve("Bar.class");
+
+ return new Object[][] {
+ { CLASSES_DIR, new String[] {
+ "java.base/jdk.internal.misc",
+ "java.base/sun.security.util",
+ "java.sql",
+ "java.xml/jdk.xml.internal",
+ "jdk.unsupported",
+ "unnamed module: lib"
+ }
+ },
+
+
+ { FOO_CLASS, new String[] {
+ "java.base",
+ "java.sql",
+ "unnamed module: lib"
+ }
+ },
+
+ { BAR_CLASS, new String[] {
+ "java.base/sun.security.util",
+ "java.xml/jdk.xml.internal",
+ }
+ },
+
+ { UNSAFE_CLASS, new String[] {
+ "java.base/jdk.internal.misc",
+ "jdk.unsupported",
+ }
+ },
+ };
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/listdeps/src/lib/Lib.java Mon Oct 31 18:06:03 2016 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package lib;
+
+import javax.xml.stream.XMLInputFactory;
+
+public class Lib {
+ public static final String isCoalescing = XMLInputFactory.IS_COALESCING;
+ public static boolean check() { return true; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/listdeps/src/z/Bar.java Mon Oct 31 18:06:03 2016 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package z;
+
+import sun.security.util.HostnameChecker;
+import jdk.xml.internal.JdkXmlUtils;
+
+public class Bar {
+ // internal API from java.xml
+ private static final String name = JdkXmlUtils.USE_CATALOG;
+
+ public static void main(String[] argv) throws Exception {
+ HostnameChecker hc = HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/listdeps/src/z/Foo.java Mon Oct 31 18:06:03 2016 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package z;
+
+import java.sql.Driver;
+import java.util.logging.Logger;
+import javax.xml.stream.XMLInputFactory;
+/*
+ * Dependences on java.sql and java.logging which can be reduced.
+ */
+public class Foo {
+ // dependence to java.logging
+ static Logger log = Logger.getLogger("foo");
+ static final String isCoalescing = XMLInputFactory.IS_COALESCING;
+
+ // dependence to java.sql
+ public Driver getDriver() { return null; }
+
+ // dependence to same package
+ public Bar getBar() { return new Bar(); }
+
+ // dependence to module m
+ public String isCoalescing() { return lib.Lib.isCoalescing; }
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/listdeps/src/z/UseUnsafe.java Mon Oct 31 18:06:03 2016 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package z;
+
+import sun.misc.Unsafe;
+import jdk.internal.misc.VM;
+
+public class UseUnsafe {
+ private static Unsafe unsafe = Unsafe.getUnsafe();
+
+ private static boolean booted = VM.isBooted();
+}