8189202: (jdeps) Need jdeps output format easy for jlink --add-modules to use
Reviewed-by: sundar
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Tue Oct 17 07:11:05 2017 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Tue Oct 17 10:32:01 2017 -0700
@@ -38,8 +38,6 @@
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.*;
-import java.util.function.Function;
-import java.util.function.ToIntFunction;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
@@ -157,6 +155,7 @@
GENERATE_OPEN_MODULE("--generate-open-module"),
LIST_DEPS("--list-deps"),
LIST_REDUCED_DEPS("--list-reduced-deps"),
+ PRINT_MODULE_DEPS("--print-module-deps"),
CHECK_MODULES("--check");
private final String[] names;
@@ -339,7 +338,7 @@
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
- task.command = task.listModuleDeps(false);
+ task.command = task.listModuleDeps(CommandOption.LIST_DEPS);
}
},
new Option(false, CommandOption.LIST_REDUCED_DEPS) {
@@ -347,7 +346,15 @@
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
- task.command = task.listModuleDeps(true);
+ task.command = task.listModuleDeps(CommandOption.LIST_REDUCED_DEPS);
+ }
+ },
+ new Option(false, CommandOption.PRINT_MODULE_DEPS) {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (task.command != null) {
+ throw new BadArgs("err.command.set", task.command, opt);
+ }
+ task.command = task.listModuleDeps(CommandOption.PRINT_MODULE_DEPS);
}
},
@@ -534,14 +541,15 @@
boolean run() throws IOException {
try (JdepsConfiguration config = buildConfig(command.allModules())) {
-
- // detect split packages
- config.splitPackages().entrySet()
- .stream()
- .sorted(Map.Entry.comparingByKey())
- .forEach(e -> log.println(getMessage("split.package",
- e.getKey(),
- e.getValue().toString())));
+ if (!options.nowarning) {
+ // detect split packages
+ config.splitPackages().entrySet()
+ .stream()
+ .sorted(Map.Entry.comparingByKey())
+ .forEach(e -> warning("warn.split.package",
+ e.getKey(),
+ e.getValue().stream().collect(joining(" "))));
+ }
// check if any module specified in --add-modules, --require, and -m is missing
options.addmods.stream()
@@ -606,9 +614,17 @@
return new GenModuleInfo(dir, openModule);
}
- private ListModuleDeps listModuleDeps(boolean reduced) throws BadArgs {
- return reduced ? new ListReducedDeps()
- : new ListModuleDeps();
+ private ListModuleDeps listModuleDeps(CommandOption option) throws BadArgs {
+ switch (option) {
+ case LIST_DEPS:
+ return new ListModuleDeps(option, true, false);
+ case LIST_REDUCED_DEPS:
+ return new ListModuleDeps(option, true, true);
+ case PRINT_MODULE_DEPS:
+ return new ListModuleDeps(option, false, true, ",");
+ default:
+ throw new IllegalArgumentException(option.toString());
+ }
}
private CheckModuleDeps checkModuleDeps(Set<String> mods) throws BadArgs {
@@ -964,20 +980,18 @@
}
}
- class ListReducedDeps extends ListModuleDeps {
- ListReducedDeps() {
- super(CommandOption.LIST_REDUCED_DEPS, true);
+ class ListModuleDeps extends Command {
+ final boolean jdkinternals;
+ final boolean reduced;
+ final String separator;
+ ListModuleDeps(CommandOption option, boolean jdkinternals, boolean reduced) {
+ this(option, jdkinternals, reduced, System.getProperty("line.separator"));
}
- }
-
- class ListModuleDeps extends Command {
- final boolean reduced;
- ListModuleDeps() {
- this(CommandOption.LIST_DEPS, false);
- }
- ListModuleDeps(CommandOption option, boolean reduced) {
+ ListModuleDeps(CommandOption option, boolean jdkinternals, boolean reduced, String sep) {
super(option);
+ this.jdkinternals = jdkinternals;
this.reduced = reduced;
+ this.separator = sep;
}
@Override
@@ -1007,8 +1021,10 @@
boolean run(JdepsConfiguration config) throws IOException {
return new ModuleExportsAnalyzer(config,
dependencyFilter(config),
+ jdkinternals,
reduced,
- log).run();
+ log,
+ separator).run();
}
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java Tue Oct 17 07:11:05 2017 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java Tue Oct 17 10:32:01 2017 -0700
@@ -33,11 +33,10 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-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.
@@ -50,17 +49,23 @@
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 showJdkInternals;
private final boolean reduced;
private final PrintWriter writer;
+ private final String separator;
public ModuleExportsAnalyzer(JdepsConfiguration config,
JdepsFilter filter,
+ boolean showJdkInternals,
boolean reduced,
- PrintWriter writer) {
+ PrintWriter writer,
+ String separator) {
super(config, filter, null,
Analyzer.Type.PACKAGE,
false /* all classes */);
+ this.showJdkInternals = showJdkInternals;
this.reduced = reduced;
this.writer = writer;
+ this.separator = separator;
}
@Override
@@ -76,7 +81,7 @@
.computeIfAbsent(targetArchive, _k -> new HashSet<>());
Module module = targetArchive.getModule();
- if (originArchive.getModule() != module &&
+ if (showJdkInternals && originArchive.getModule() != module &&
module.isJDK() && !module.isExported(target)) {
// use of JDK internal APIs
jdkInternals.add(target);
@@ -89,35 +94,19 @@
.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));
-
+ Set<Module> modules = modules();
+ if (showJdkInternals) {
+ // print modules and JDK internal API dependences
+ printDependences(modules);
+ } else {
+ // print module dependences
+ writer.println(modules.stream().map(Module::name).sorted()
+ .collect(Collectors.joining(separator)));
+ }
return rc;
}
- private void printDependences() {
- // find use of JDK internals
- Map<Module, Set<String>> jdkinternals = new HashMap<>();
- dependenceStream()
- .flatMap(map -> map.entrySet().stream())
- .filter(e -> e.getValue().size() > 0)
- .forEach(e -> jdkinternals.computeIfAbsent(e.getKey().getModule(),
- _k -> new HashSet<>())
- .addAll(e.getValue()));
-
-
+ private Set<Module> modules() {
// build module graph
ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration);
Module root = new RootModule("root");
@@ -126,43 +115,38 @@
dependenceStream()
.flatMap(map -> map.keySet().stream())
.filter(m -> m.getModule().isNamed()
- && !configuration.rootModules().contains(m))
+ && !configuration.rootModules().contains(m))
.map(Archive::getModule)
.forEach(m -> builder.addEdge(root, m));
- // module dependences
- Set<Module> modules = builder.build().adjacentNodes(root);
-
+ // build module dependence graph
// if reduced is set, apply transition reduction
- Set<Module> reducedSet;
- if (reduced) {
- Set<Module> nodes = builder.reduced().adjacentNodes(root);
- if (nodes.size() == 1) {
- // java.base only
- reducedSet = nodes;
- } else {
- // java.base is mandated and can be excluded from the reduced graph
- reducedSet = nodes.stream()
- .filter(m -> !"java.base".equals(m.name()) ||
- jdkinternals.containsKey("java.base"))
- .collect(Collectors.toSet());
- }
- } else {
- reducedSet = modules;
- }
+ Graph<Module> g = reduced ? builder.reduced() : builder.build();
+ return g.adjacentNodes(root);
+ }
- 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 void printDependences(Set<Module> modules) {
+ // find use of JDK internals
+ Map<Module, Set<String>> jdkinternals = new HashMap<>();
+ dependenceStream()
+ .flatMap(map -> map.entrySet().stream())
+ .filter(e -> e.getValue().size() > 0)
+ .forEach(e -> jdkinternals.computeIfAbsent(e.getKey().getModule(),
+ _k -> new TreeSet<>())
+ .addAll(e.getValue()));
+
+ // print modules and JDK internal API dependences
+ Stream.concat(modules.stream(), jdkinternals.keySet().stream())
+ .sorted(Comparator.comparing(Module::name))
+ .distinct()
+ .forEach(m -> {
+ if (jdkinternals.containsKey(m)) {
+ jdkinternals.get(m).stream()
+ .forEach(pn -> writer.format(" %s/%s%s", m, pn, separator));
+ } else {
+ writer.format(" %s%s", m, separator);
+ }
+ });
}
/*
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Tue Oct 17 07:11:05 2017 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Tue Oct 17 10:32:01 2017 -0700
@@ -157,23 +157,31 @@
\ WARNING: JDK internal APIs are inaccessible.
main.opt.list-deps=\
-\ --list-deps Lists the module dependences and also the\n\
-\ package names of JDK internal APIs if referenced.
+\ --list-deps Lists the module dependences. It also prints\n\
+\ any JDK internal API packages if referenced.\n\
+\ This option does not show dependences on the\n\
+\ class path or not found.
main.opt.list-reduced-deps=\
\ --list-reduced-deps Same as --list-deps with not listing\n\
-\ the implied reads edges from the module graph\n\
+\ the implied reads edges from the module graph.\n\
\ If module M1 reads M2, and M2 requires\n\
\ transitive on M3, then M1 reading M3 is implied\n\
\ and is not shown in the graph.
+main.opt.print-module-deps=\
+\ --print-module-deps Same as --list-reduced-deps with printing\n\
+\ a comma-separated list of module dependences.\n\
+\ This output can be used by jlink --add-modules\n\
+\ in order to create a custom image containing\n\
+\ those modules and their transitive dependences.
+
main.opt.depth=\
\ -depth=<depth> Specify the depth of the transitive\n\
\ dependency analysis
main.opt.q=\
-\ -q -quiet Do not show missing dependences from \n\
-\ --generate-module-info output.
+\ -q -quiet Suppress warning messages
main.opt.multi-release=\
\ --multi-release <version> Specifies the version when processing\n\
@@ -202,7 +210,7 @@
err.multirelease.jar.malformed=malformed multi-release jar, {0}, bad entry: {1}
warn.invalid.arg=Path does not exist: {0}
warn.skipped.entry={0}
-warn.split.package=package {0} defined in {1} {2}
+warn.split.package=split package: {0} {1}
warn.replace.useJDKInternals=\
JDK internal APIs are unsupported and private to JDK implementation that are\n\
subject to be removed or changed incompatibly and could break your application.\n\
@@ -210,7 +218,6 @@
For the most recent update on JDK internal API replacements, please check:\n\
{0}
-split.package=split package: {0} {1}\n
inverse.transitive.dependencies.on=Inverse transitive dependences on {0}
inverse.transitive.dependencies.matching=Inverse transitive dependences matching {0}
internal.api.column.header=JDK Internal API
--- a/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java Tue Oct 17 07:11:05 2017 -0700
+++ b/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java Tue Oct 17 10:32:01 2017 -0700
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8167057
- * @summary Tests --list-deps and --list-reduced-deps options
+ * @summary Tests --list-deps, --list-reduced-deps, --print-module-deps options
* @modules java.logging
* java.xml
* jdk.compiler
@@ -38,6 +38,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
+import java.util.stream.Collectors;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
@@ -139,8 +140,7 @@
"java.logging",
"java.sql",
"java.xml/jdk.xml.internal",
- "jdk.unsupported",
- "unnamed module: lib"
+ "jdk.unsupported"
}
},
@@ -153,8 +153,7 @@
"java.base",
"java.logging",
"java.sql",
- "java.xml",
- "unnamed module: lib"
+ "java.xml"
}
},
@@ -166,7 +165,7 @@
{ UNSAFE_CLASS, new String[] {
"java.base/jdk.internal.misc",
- "jdk.unsupported",
+ "jdk.unsupported"
}
},
};
@@ -182,8 +181,7 @@
"java.base/sun.security.util",
"java.sql",
"java.xml/jdk.xml.internal",
- "jdk.unsupported",
- "unnamed module: lib"
+ "jdk.unsupported"
}
},
@@ -193,8 +191,8 @@
},
{ FOO_CLASS, new String[] {
- "java.sql",
- "unnamed module: lib"
+ "java.base",
+ "java.sql"
}
},
@@ -206,10 +204,36 @@
{ UNSAFE_CLASS, new String[] {
"java.base/jdk.internal.misc",
- "jdk.unsupported",
+ "jdk.unsupported"
}
},
};
}
+ @Test(dataProvider = "moduledeps")
+ public void testPrintModuleDeps(Path classes, String expected) {
+ JdepsRunner jdeps = JdepsRunner.run(
+ "--class-path", LIB_DIR.toString(),
+ "--print-module-deps", classes.toString()
+ );
+ String output = Arrays.stream(jdeps.output())
+ .map(s -> s.trim())
+ .collect(Collectors.joining(","));
+ assertEquals(output, expected);
+ }
+
+
+ @DataProvider(name = "moduledeps")
+ public Object[][] moduledeps() {
+ Path barClass = CLASSES_DIR.resolve("z").resolve("Bar.class");
+
+ return new Object[][] {
+ // java.xml is an implied reads edge from java.sql
+ { CLASSES_DIR, "java.base,java.sql,jdk.unsupported"},
+ { HI_CLASS, "java.base"},
+ { FOO_CLASS, "java.base,java.sql"},
+ { BAR_CLASS, "java.base,java.xml"},
+ { UNSAFE_CLASS, "java.base,jdk.unsupported"},
+ };
+ }
}