8189202: (jdeps) Need jdeps output format easy for jlink --add-modules to use
Reviewed-by: sundar
This commit is contained in:
parent
8315ac39cc
commit
9ebc72545b
@ -38,8 +38,6 @@ import java.nio.file.Path;
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
|
||||
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 @@ class JdepsTask {
|
||||
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 JdepsTask {
|
||||
}
|
||||
}
|
||||
|
||||
class ListReducedDeps extends ListModuleDeps {
|
||||
ListReducedDeps() {
|
||||
super(CommandOption.LIST_REDUCED_DEPS, true);
|
||||
}
|
||||
}
|
||||
|
||||
class ListModuleDeps extends Command {
|
||||
final boolean jdkinternals;
|
||||
final boolean reduced;
|
||||
ListModuleDeps() {
|
||||
this(CommandOption.LIST_DEPS, false);
|
||||
final String separator;
|
||||
ListModuleDeps(CommandOption option, boolean jdkinternals, boolean reduced) {
|
||||
this(option, jdkinternals, reduced, System.getProperty("line.separator"));
|
||||
}
|
||||
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 @@ class JdepsTask {
|
||||
boolean run(JdepsConfiguration config) throws IOException {
|
||||
return new ModuleExportsAnalyzer(config,
|
||||
dependencyFilter(config),
|
||||
jdkinternals,
|
||||
reduced,
|
||||
log).run();
|
||||
log,
|
||||
separator).run();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,11 +33,10 @@ import java.util.HashMap;
|
||||
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 @@ import static com.sun.tools.jdeps.Analyzer.NOT_FOUND;
|
||||
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 @@ public class ModuleExportsAnalyzer extends DepsAnalyzer {
|
||||
.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 @@ public class ModuleExportsAnalyzer extends DepsAnalyzer {
|
||||
.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 @@ public class ModuleExportsAnalyzer extends DepsAnalyzer {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -157,23 +157,31 @@ main.opt.jdkinternals=\
|
||||
\ 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.version.associated=class {0} already associated with version {1
|
||||
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 @@ Please modify your code to eliminate dependence on any JDK internal APIs.\n\
|
||||
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
|
||||
|
@ -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 @@ public class ListModuleDeps {
|
||||
"java.logging",
|
||||
"java.sql",
|
||||
"java.xml/jdk.xml.internal",
|
||||
"jdk.unsupported",
|
||||
"unnamed module: lib"
|
||||
"jdk.unsupported"
|
||||
}
|
||||
},
|
||||
|
||||
@ -153,8 +153,7 @@ public class ListModuleDeps {
|
||||
"java.base",
|
||||
"java.logging",
|
||||
"java.sql",
|
||||
"java.xml",
|
||||
"unnamed module: lib"
|
||||
"java.xml"
|
||||
}
|
||||
},
|
||||
|
||||
@ -166,7 +165,7 @@ public class ListModuleDeps {
|
||||
|
||||
{ UNSAFE_CLASS, new String[] {
|
||||
"java.base/jdk.internal.misc",
|
||||
"jdk.unsupported",
|
||||
"jdk.unsupported"
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -182,8 +181,7 @@ public class ListModuleDeps {
|
||||
"java.base/sun.security.util",
|
||||
"java.sql",
|
||||
"java.xml/jdk.xml.internal",
|
||||
"jdk.unsupported",
|
||||
"unnamed module: lib"
|
||||
"jdk.unsupported"
|
||||
}
|
||||
},
|
||||
|
||||
@ -193,8 +191,8 @@ public class ListModuleDeps {
|
||||
},
|
||||
|
||||
{ FOO_CLASS, new String[] {
|
||||
"java.sql",
|
||||
"unnamed module: lib"
|
||||
"java.base",
|
||||
"java.sql"
|
||||
}
|
||||
},
|
||||
|
||||
@ -206,10 +204,36 @@ public class ListModuleDeps {
|
||||
|
||||
{ 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"},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user