8213909: jdeps --print-module-deps should report missing dependences
8168869: jdeps: localized messages don't use proper line breaks
Reviewed-by: sundar
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java Wed Nov 21 22:34:01 2018 -0800
@@ -32,6 +32,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -39,6 +40,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -74,6 +76,7 @@
protected final Map<Location, Archive> locationToArchive = new HashMap<>();
static final Archive NOT_FOUND
= new Archive(JdepsTask.getMessage("artifact.not.found"));
+ static final Predicate<Archive> ANY = a -> true;
/**
* Constructs an Analyzer instance.
@@ -161,7 +164,7 @@
* Visit the dependencies of the given source.
* If the requested level is SUMMARY, it will visit the required archives list.
*/
- void visitDependences(Archive source, Visitor v, Type level) {
+ void visitDependences(Archive source, Visitor v, Type level, Predicate<Archive> targetFilter) {
if (level == Type.SUMMARY) {
final Dependences result = results.get(source);
final Set<Archive> reqs = result.requires();
@@ -184,7 +187,7 @@
Dependences result = results.get(source);
if (level != type) {
// requesting different level of analysis
- result = new Dependences(source, level);
+ result = new Dependences(source, level, targetFilter);
source.visitDependences(result);
}
result.dependencies().stream()
@@ -196,7 +199,11 @@
}
void visitDependences(Archive source, Visitor v) {
- visitDependences(source, v, type);
+ visitDependences(source, v, type, ANY);
+ }
+
+ void visitDependences(Archive source, Visitor v, Type level) {
+ visitDependences(source, v, level, ANY);
}
/**
@@ -208,12 +215,17 @@
protected final Set<Archive> requires;
protected final Set<Dep> deps;
protected final Type level;
+ protected final Predicate<Archive> targetFilter;
private Profile profile;
Dependences(Archive archive, Type level) {
+ this(archive, level, ANY);
+ }
+ Dependences(Archive archive, Type level, Predicate<Archive> targetFilter) {
this.archive = archive;
this.deps = new HashSet<>();
this.requires = new HashSet<>();
this.level = level;
+ this.targetFilter = targetFilter;
}
Set<Dep> dependencies() {
@@ -266,7 +278,7 @@
@Override
public void visit(Location o, Location t) {
Archive targetArchive = findArchive(t);
- if (filter.accepts(o, archive, t, targetArchive)) {
+ if (filter.accepts(o, archive, t, targetArchive) && targetFilter.test(targetArchive)) {
addDep(o, t);
if (archive != targetArchive && !requires.contains(targetArchive)) {
requires.add(targetArchive);
@@ -368,13 +380,21 @@
}
}
+ /*
+ * Returns true if the given archive represents not found.
+ */
+ static boolean notFound(Archive archive) {
+ return archive == NOT_FOUND || archive == REMOVED_JDK_INTERNALS;
+ }
+
static final Jdk8Internals REMOVED_JDK_INTERNALS = new Jdk8Internals();
static class Jdk8Internals extends Module {
- private final String JDK8_INTERNALS = "/com/sun/tools/jdeps/resources/jdk8_internals.txt";
+ private static final String NAME = "JDK removed internal API";
+ private static final String JDK8_INTERNALS = "/com/sun/tools/jdeps/resources/jdk8_internals.txt";
private final Set<String> jdk8Internals;
private Jdk8Internals() {
- super("JDK removed internal API");
+ super(NAME, ModuleDescriptor.newModule("jdk8internals").build(), true);
try (InputStream in = JdepsTask.class.getResourceAsStream(JDK8_INTERNALS);
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
this.jdk8Internals = reader.lines()
@@ -394,11 +414,6 @@
}
@Override
- public String name() {
- return getName();
- }
-
- @Override
public boolean isJDK() {
return true;
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java Wed Nov 21 22:34:01 2018 -0800
@@ -38,6 +38,7 @@
import java.io.IOException;
import java.io.UncheckedIOException;
+import java.nio.file.Paths;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
@@ -172,7 +173,7 @@
parsedArchives.get(finder).add(archive);
- trace("parsing %s %s%n", archive.getName(), archive.path());
+ trace("parsing %s %s%n", archive.getName(), archive.getPathName());
FutureTask<Set<Location>> task = new FutureTask<>(() -> {
Set<Location> targets = new HashSet<>();
for (ClassFile cf : archive.reader().getClassFiles()) {
@@ -206,7 +207,6 @@
parsedClasses.putIfAbsent(d.getOrigin(), archive);
}
}
-
return targets;
});
tasks.add(task);
@@ -264,8 +264,7 @@
FutureTask<Set<Location>> task;
while ((task = tasks.poll()) != null) {
// wait for completion
- if (!task.isDone())
- targets.addAll(task.get());
+ targets.addAll(task.get());
}
return targets;
} catch (InterruptedException|ExecutionException e) {
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Wed Nov 21 22:34:01 2018 -0800
@@ -83,42 +83,27 @@
private final List<Archive> classpathArchives = new ArrayList<>();
private final List<Archive> initialArchives = new ArrayList<>();
private final Set<Module> rootModules = new HashSet<>();
- private final Configuration configuration;
private final Runtime.Version version;
- private JdepsConfiguration(SystemModuleFinder systemModulePath,
+ private JdepsConfiguration(Configuration config,
+ SystemModuleFinder systemModulePath,
ModuleFinder finder,
Set<String> roots,
List<Path> classpaths,
List<Archive> initialArchives,
- Set<String> tokens,
Runtime.Version version)
throws IOException
{
trace("root: %s%n", roots);
-
+ trace("initial archives: %s%n", initialArchives);
+ trace("class path: %s%n", classpaths);
this.system = systemModulePath;
this.finder = finder;
this.version = version;
- // build root set for resolution
- Set<String> mods = new HashSet<>(roots);
- if (tokens.contains(ALL_SYSTEM)) {
- systemModulePath.findAll().stream()
- .map(mref -> mref.descriptor().name())
- .forEach(mods::add);
- }
-
- if (tokens.contains(ALL_DEFAULT)) {
- mods.addAll(systemModulePath.defaultSystemRoots());
- }
-
- this.configuration = Configuration.empty()
- .resolve(finder, ModuleFinder.of(), mods);
-
- this.configuration.modules().stream()
- .map(ResolvedModule::reference)
- .forEach(this::addModuleReference);
+ config.modules().stream()
+ .map(ResolvedModule::reference)
+ .forEach(this::addModuleReference);
// packages in unnamed module
initialArchives.forEach(archive -> {
@@ -538,14 +523,6 @@
.forEach(rootModules::add);
}
- // add all modules to the root set for unnamed module or set explicitly
- boolean unnamed = !initialArchives.isEmpty() || !classPaths.isEmpty();
- if ((unnamed || tokens.contains(ALL_MODULE_PATH)) && appModulePath != null) {
- appModulePath.findAll().stream()
- .map(mref -> mref.descriptor().name())
- .forEach(rootModules::add);
- }
-
// no archive is specified for analysis
// add all system modules as root if --add-modules ALL-SYSTEM is specified
if (tokens.contains(ALL_SYSTEM) && rootModules.isEmpty() &&
@@ -556,16 +533,41 @@
.forEach(rootModules::add);
}
- if (unnamed && !tokens.contains(ALL_DEFAULT)) {
- tokens.add(ALL_SYSTEM);
+ // add all modules on app module path as roots if ALL-MODULE-PATH is specified
+ if ((tokens.contains(ALL_MODULE_PATH)) && appModulePath != null) {
+ appModulePath.findAll().stream()
+ .map(mref -> mref.descriptor().name())
+ .forEach(rootModules::add);
}
- return new JdepsConfiguration(systemModulePath,
+
+ // build root set for module resolution
+ Set<String> mods = new HashSet<>(rootModules);
+ // if archives are specified for analysis, then consider as unnamed module
+ boolean unnamed = !initialArchives.isEmpty() || !classPaths.isEmpty();
+ if (tokens.contains(ALL_DEFAULT)) {
+ mods.addAll(systemModulePath.defaultSystemRoots());
+ } else if (tokens.contains(ALL_SYSTEM) || unnamed) {
+ // resolve all system modules as unnamed module may reference any class
+ systemModulePath.findAll().stream()
+ .map(mref -> mref.descriptor().name())
+ .forEach(mods::add);
+ }
+ if (unnamed && appModulePath != null) {
+ // resolve all modules on module path as unnamed module may reference any class
+ appModulePath.findAll().stream()
+ .map(mref -> mref.descriptor().name())
+ .forEach(mods::add);
+ }
+
+ // resolve the module graph
+ Configuration config = Configuration.empty().resolve(finder, ModuleFinder.of(), mods);
+ return new JdepsConfiguration(config,
+ systemModulePath,
finder,
rootModules,
classPaths,
initialArchives,
- tokens,
version);
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java Wed Nov 21 22:34:01 2018 -0800
@@ -55,6 +55,7 @@
private final boolean filterSamePackage;
private final boolean filterSameArchive;
private final boolean findJDKInternals;
+ private final boolean findMissingDeps;
private final Pattern includePattern;
private final Set<String> requires;
@@ -64,6 +65,7 @@
boolean filterSamePackage,
boolean filterSameArchive,
boolean findJDKInternals,
+ boolean findMissingDeps,
Pattern includePattern,
Set<String> requires) {
this.filter = filter;
@@ -71,6 +73,7 @@
this.filterSamePackage = filterSamePackage;
this.filterSameArchive = filterSameArchive;
this.findJDKInternals = findJDKInternals;
+ this.findMissingDeps = findMissingDeps;
this.includePattern = includePattern;
this.requires = requires;
}
@@ -153,6 +156,8 @@
Module module = targetArchive.getModule();
return originArchive != targetArchive &&
isJDKInternalPackage(module, target.getPackageName());
+ } else if (findMissingDeps) {
+ return Analyzer.notFound(targetArchive);
} else if (filterSameArchive) {
// accepts origin and target that from different archive
return originArchive != targetArchive;
@@ -188,6 +193,7 @@
boolean filterSamePackage;
boolean filterSameArchive;
boolean findJDKInterals;
+ boolean findMissingDeps;
// source filters
Pattern includePattern;
Set<String> requires = new HashSet<>();
@@ -221,6 +227,10 @@
this.findJDKInterals = value;
return this;
}
+ public Builder findMissingDeps(boolean value) {
+ this.findMissingDeps = value;
+ return this;
+ }
public Builder includePattern(Pattern regex) {
this.includePattern = regex;
return this;
@@ -238,6 +248,7 @@
filterSamePackage,
filterSameArchive,
findJDKInterals,
+ findMissingDeps,
includePattern,
requires);
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Nov 21 22:34:01 2018 -0800
@@ -357,6 +357,11 @@
task.command = task.listModuleDeps(CommandOption.PRINT_MODULE_DEPS);
}
},
+ new Option(false, "--ignore-missing-deps") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.ignoreMissingDeps = true;
+ }
+ },
// ---- Target filtering options ----
new Option(true, "-p", "-package", "--package") {
@@ -401,6 +406,11 @@
}
}
},
+ new Option(false, "--missing-deps") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.findMissingDeps = true;
+ }
+ },
// ---- Source filtering options ----
new Option(true, "-include") {
@@ -415,15 +425,19 @@
}
},
- new Option(false, "-R", "-recursive") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.depth = 0;
+ new Option(false, "-R", "-recursive", "--recursive") {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ task.options.recursive = Options.RECURSIVE;
// turn off filtering
task.options.filterSameArchive = false;
task.options.filterSamePackage = false;
}
},
-
+ new Option(false, "--no-recursive") {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ task.options.recursive = Options.NO_RECURSIVE;
+ }
+ },
new Option(false, "-I", "--inverse") {
void process(JdepsTask task, String opt, String arg) {
task.options.inverse = true;
@@ -437,9 +451,9 @@
new Option(false, "--compile-time") {
void process(JdepsTask task, String opt, String arg) {
task.options.compileTimeView = true;
+ task.options.recursive = Options.RECURSIVE;
task.options.filterSamePackage = true;
task.options.filterSameArchive = true;
- task.options.depth = 0;
}
},
@@ -611,6 +625,13 @@
}
private ListModuleDeps listModuleDeps(CommandOption option) throws BadArgs {
+ // do transitive dependence analysis unless --no-recursive is set
+ if (options.recursive != Options.NO_RECURSIVE) {
+ options.recursive = Options.RECURSIVE;
+ }
+ // no need to record the dependences on the same archive or same package
+ options.filterSameArchive = true;
+ options.filterSamePackage = true;
switch (option) {
case LIST_DEPS:
return new ListModuleDeps(option, true, false);
@@ -677,16 +698,16 @@
@Override
boolean checkOptions() {
- if (options.findJDKInternals) {
+ if (options.findJDKInternals || options.findMissingDeps) {
// cannot set any filter, -verbose and -summary option
if (options.showSummary || options.verbose != null) {
reportError("err.invalid.options", "-summary or -verbose",
- "-jdkinternals");
+ options.findJDKInternals ? "-jdkinternals" : "--missing-deps");
return false;
}
if (options.hasFilter()) {
reportError("err.invalid.options", "--package, --regex, --require",
- "-jdkinternals");
+ options.findJDKInternals ? "-jdkinternals" : "--missing-deps");
return false;
}
}
@@ -715,7 +736,7 @@
if (options.showSummary)
return Type.SUMMARY;
- if (options.findJDKInternals)
+ if (options.findJDKInternals || options.findMissingDeps)
return Type.CLASS;
// default to package-level verbose
@@ -744,7 +765,7 @@
type,
options.apiOnly);
- boolean ok = analyzer.run(options.compileTimeView, options.depth);
+ boolean ok = analyzer.run(options.compileTimeView, options.depth());
// print skipped entries, if any
if (!options.nowarning) {
@@ -797,8 +818,8 @@
@Override
boolean checkOptions() {
- if (options.depth != 1) {
- reportError("err.invalid.options", "-R", "--inverse");
+ if (options.recursive != -1 || options.depth != -1) {
+ reportError("err.invalid.options", "--recursive and --no-recursive", "--inverse");
return false;
}
@@ -925,12 +946,7 @@
if (!ok && !options.nowarning) {
reportError("err.missing.dependences");
- builder.visitMissingDeps(
- (origin, originArchive, target, targetArchive) -> {
- if (builder.notFound(targetArchive))
- log.format(" %-50s -> %-50s %s%n",
- origin, target, targetArchive.getName());
- });
+ builder.visitMissingDeps(new SimpleDepVisitor());
}
return ok;
}
@@ -993,13 +1009,15 @@
@Override
boolean checkOptions() {
if (options.showSummary || options.verbose != null) {
- reportError("err.invalid.options", "-summary or -verbose",
- option);
+ reportError("err.invalid.options", "-summary or -verbose", option);
return false;
}
if (options.findJDKInternals) {
- reportError("err.invalid.options", "-jdkinternals",
- option);
+ reportError("err.invalid.options", "-jdkinternals", option);
+ return false;
+ }
+ if (options.findMissingDeps) {
+ reportError("err.invalid.options", "--missing-deps", option);
return false;
}
@@ -1015,16 +1033,22 @@
@Override
boolean run(JdepsConfiguration config) throws IOException {
- return new ModuleExportsAnalyzer(config,
- dependencyFilter(config),
- jdkinternals,
- reduced,
- log,
- separator).run();
+ ModuleExportsAnalyzer analyzer = new ModuleExportsAnalyzer(config,
+ dependencyFilter(config),
+ jdkinternals,
+ reduced,
+ log,
+ separator);
+ boolean ok = analyzer.run(options.depth(), options.ignoreMissingDeps);
+ if (!ok) {
+ reportError("err.cant.list.module.deps");
+ log.println();
+ analyzer.visitMissingDeps(new SimpleDepVisitor());
+ }
+ return ok;
}
}
-
class GenDotFile extends AnalyzeDeps {
final Path dotOutputDir;
GenDotFile(Path dotOutputDir) {
@@ -1053,6 +1077,18 @@
}
}
+ class SimpleDepVisitor implements Analyzer.Visitor {
+ private Archive source;
+ @Override
+ public void visitDependence(String origin, Archive originArchive, String target, Archive targetArchive) {
+ if (source != originArchive) {
+ source = originArchive;
+ log.format("%s%n", originArchive);
+ }
+ log.format(" %-50s -> %-50s %s%n", origin, target, targetArchive.getName());
+ }
+ }
+
/**
* Returns a filter used during dependency analysis
*/
@@ -1066,6 +1102,7 @@
// target filters
builder.filter(options.filterSamePackage, options.filterSameArchive);
builder.findJDKInternals(options.findJDKInternals);
+ builder.findMissingDeps(options.findMissingDeps);
// --require
if (!options.requires.isEmpty()) {
@@ -1158,11 +1195,8 @@
private String version(String key) {
// key=version: mm.nn.oo[-milestone]
// key=full: mm.mm.oo[-milestone]-build
- if (ResourceBundleHelper.versionRB == null) {
- return System.getProperty("java.version");
- }
try {
- return ResourceBundleHelper.versionRB.getString(key);
+ return ResourceBundleHelper.getVersion(key);
} catch (MissingResourceException e) {
return getMessage("version.unknown", System.getProperty("java.version"));
}
@@ -1170,13 +1204,15 @@
static String getMessage(String key, Object... args) {
try {
- return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
+ return MessageFormat.format(ResourceBundleHelper.getMessage(key), args);
} catch (MissingResourceException e) {
throw new InternalError("Missing message: " + key);
}
}
private static class Options {
+ static final int NO_RECURSIVE = 0;
+ static final int RECURSIVE = 1;
boolean help;
boolean version;
boolean fullVersion;
@@ -1186,6 +1222,8 @@
boolean apiOnly;
boolean showLabel;
boolean findJDKInternals;
+ boolean findMissingDeps;
+ boolean ignoreMissingDeps;
boolean nowarning = false;
Analyzer.Type verbose;
// default filter references from same package
@@ -1193,7 +1231,8 @@
boolean filterSameArchive = false;
Pattern filterRegex;
String classpath;
- int depth = 1;
+ int recursive = -1; // 0: --no-recursive, 1: --recursive
+ int depth = -1;
Set<String> requires = new HashSet<>();
Set<String> packageNames = new HashSet<>();
Pattern regex; // apply to the dependences
@@ -1222,9 +1261,23 @@
if (packageNames.size() > 0) count++;
return count;
}
+
+ int depth() {
+ // ignore -depth if --no-recursive is set
+ if (recursive == NO_RECURSIVE)
+ return 1;
+
+ // depth == 0 if recursive
+ if (recursive == RECURSIVE && depth == -1)
+ return 0;
+
+ // default depth is 1 unless specified via -depth option
+ return depth == -1 ? 1 : depth;
+ }
}
private static class ResourceBundleHelper {
+ static final String LS = System.lineSeparator();
static final ResourceBundle versionRB;
static final ResourceBundle bundle;
static final ResourceBundle jdkinternals;
@@ -1247,6 +1300,21 @@
throw new InternalError("Cannot find jdkinternals resource bundle");
}
}
+
+ static String getMessage(String key) {
+ return bundle.getString(key).replace("\n", LS);
+ }
+
+ static String getVersion(String key) {
+ if (ResourceBundleHelper.versionRB == null) {
+ return System.getProperty("java.version");
+ }
+ return versionRB.getString(key).replace("\n", LS);
+ }
+
+ static String getSuggestedReplacement(String key) {
+ return ResourceBundleHelper.jdkinternals.getString(key).replace("\n", LS);
+ }
}
/**
@@ -1258,7 +1326,7 @@
String value = null;
while (value == null && name != null) {
try {
- value = ResourceBundleHelper.jdkinternals.getString(name);
+ value = ResourceBundleHelper.getSuggestedReplacement(name);
} catch (MissingResourceException e) {
// go up one subpackage level
int i = name.lastIndexOf('.');
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java Wed Nov 21 22:34:01 2018 -0800
@@ -58,12 +58,16 @@
private final URI location;
protected Module(String name) {
+ this(name, null, false);
+ }
+
+ protected Module(String name, ModuleDescriptor descriptor, boolean isSystem) {
super(name);
- this.descriptor = null;
+ this.descriptor = descriptor;
this.location = null;
this.exports = Collections.emptyMap();
this.opens = Collections.emptyMap();
- this.isSystem = true;
+ this.isSystem = isSystem;
}
private Module(String name,
@@ -89,11 +93,11 @@
}
public boolean isNamed() {
- return true;
+ return descriptor != null;
}
public boolean isAutomatic() {
- return descriptor.isAutomatic();
+ return descriptor != null && descriptor.isAutomatic();
}
public Module getModule() {
@@ -232,9 +236,7 @@
private static class UnnamedModule extends Module {
private UnnamedModule() {
- super("unnamed", null, null,
- Collections.emptyMap(), Collections.emptyMap(),
- false, null);
+ super("unnamed", null, false);
}
@Override
@@ -243,16 +245,6 @@
}
@Override
- public boolean isNamed() {
- return false;
- }
-
- @Override
- public boolean isAutomatic() {
- return false;
- }
-
- @Override
public boolean isExported(String pn) {
return true;
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java Wed Nov 21 22:34:01 2018 -0800
@@ -49,42 +49,47 @@
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 Map<String, Set<String>> missingDeps = new HashMap<>();
+ private final boolean showInternals;
private final boolean reduced;
private final PrintWriter writer;
private final String separator;
public ModuleExportsAnalyzer(JdepsConfiguration config,
JdepsFilter filter,
- boolean showJdkInternals,
+ boolean showInternals,
boolean reduced,
PrintWriter writer,
String separator) {
super(config, filter, null,
Analyzer.Type.PACKAGE,
false /* all classes */);
- this.showJdkInternals = showJdkInternals;
+ this.showInternals = showInternals;
this.reduced = reduced;
this.writer = writer;
this.separator = separator;
}
- @Override
- public boolean run() throws IOException {
- // analyze dependences
- boolean rc = super.run();
+ public boolean run(int maxDepth, boolean ignoreMissingDeps) throws IOException {
+ // use compile time view so that the entire archive on classpath is analyzed
+ boolean rc = super.run(true, maxDepth);
// A visitor to record the module-level dependences as well as
- // use of JDK internal APIs
+ // use of internal APIs
Analyzer.Visitor visitor = (origin, originArchive, target, targetArchive) -> {
- Set<String> jdkInternals =
+ Set<String> internals =
deps.computeIfAbsent(originArchive, _k -> new HashMap<>())
.computeIfAbsent(targetArchive, _k -> new HashSet<>());
Module module = targetArchive.getModule();
- if (showJdkInternals && originArchive.getModule() != module &&
- module.isJDK() && !module.isExported(target)) {
- // use of JDK internal APIs
- jdkInternals.add(target);
+ if (showInternals && originArchive.getModule() != module &&
+ module.isNamed() && !module.isExported(target, module.name())) {
+ // use of internal APIs
+ internals.add(target);
+ }
+ if (!ignoreMissingDeps && Analyzer.notFound(targetArchive)) {
+ Set<String> notFound =
+ missingDeps.computeIfAbsent(origin, _k -> new HashSet<>());
+ notFound.add(target);
}
};
@@ -94,10 +99,26 @@
.sorted(Comparator.comparing(Archive::getName))
.forEach(archive -> analyzer.visitDependences(archive, visitor));
+ // error if any missing dependence
+ if (!rc || !missingDeps.isEmpty()) {
+ return false;
+ }
+
+ Map<Module, Set<String>> internalPkgs = internalPackages();
Set<Module> modules = modules();
- if (showJdkInternals) {
+ if (showInternals) {
// print modules and JDK internal API dependences
- printDependences(modules);
+ Stream.concat(modules.stream(), internalPkgs.keySet().stream())
+ .sorted(Comparator.comparing(Module::name))
+ .distinct()
+ .forEach(m -> {
+ if (internalPkgs.containsKey(m)) {
+ internalPkgs.get(m).stream()
+ .forEach(pn -> writer.format(" %s/%s%s", m, pn, separator));
+ } else {
+ writer.format(" %s%s", m, separator);
+ }
+ });
} else {
// print module dependences
writer.println(modules.stream().map(Module::name).sorted()
@@ -106,16 +127,28 @@
return rc;
}
+ /*
+ * Prints missing dependences
+ */
+ void visitMissingDeps(Analyzer.Visitor visitor) {
+ archives.stream()
+ .filter(analyzer::hasDependences)
+ .sorted(Comparator.comparing(Archive::getName))
+ .filter(m -> analyzer.requires(m).anyMatch(Analyzer::notFound))
+ .forEach(m -> {
+ analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE, Analyzer::notFound);
+ });
+ }
+
private Set<Module> modules() {
// build module graph
ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration);
- Module root = new RootModule("root");
+ Module root = new RootModule();
builder.addModule(root);
// find named module dependences
dependenceStream()
.flatMap(map -> map.keySet().stream())
- .filter(m -> m.getModule().isNamed()
- && !configuration.rootModules().contains(m))
+ .filter(m -> m.getModule().isNamed() && !configuration.rootModules().contains(m))
.map(Archive::getModule)
.forEach(m -> builder.addEdge(root, m));
@@ -125,28 +158,15 @@
return g.adjacentNodes(root);
}
- private void printDependences(Set<Module> modules) {
- // find use of JDK internals
- Map<Module, Set<String>> jdkinternals = new HashMap<>();
+ private Map<Module, Set<String>> internalPackages() {
+ Map<Module, Set<String>> internalPkgs = new HashMap<>();
dependenceStream()
.flatMap(map -> map.entrySet().stream())
.filter(e -> e.getValue().size() > 0)
- .forEach(e -> jdkinternals.computeIfAbsent(e.getKey().getModule(),
- _k -> new TreeSet<>())
+ .forEach(e -> internalPkgs.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);
- }
- });
+ return internalPkgs;
}
/*
@@ -160,18 +180,13 @@
.map(deps::get);
}
- private class RootModule extends Module {
- final ModuleDescriptor descriptor;
- RootModule(String name) {
- super(name);
-
- ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(name);
- this.descriptor = builder.build();
- }
-
- @Override
- public ModuleDescriptor descriptor() {
- return descriptor;
+ /*
+ * RootModule serves as the root node for building the module graph
+ */
+ private static class RootModule extends Module {
+ static final String NAME = "root";
+ RootModule() {
+ super(NAME, ModuleDescriptor.newModule(NAME).build(), false);
}
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java Wed Nov 21 22:34:01 2018 -0800
@@ -137,17 +137,13 @@
}
}
- boolean notFound(Archive m) {
- return m == NOT_FOUND || m == REMOVED_JDK_INTERNALS;
- }
-
private Module toNormalModule(Module module, Set<Archive> requiresTransitive)
throws IOException
{
// done analysis
module.close();
- if (analyzer.requires(module).anyMatch(this::notFound)) {
+ if (analyzer.requires(module).anyMatch(Analyzer::notFound)) {
// missing dependencies
return null;
}
@@ -182,9 +178,9 @@
void visitMissingDeps(Analyzer.Visitor visitor) {
automaticModules().stream()
- .filter(m -> analyzer.requires(m).anyMatch(this::notFound))
+ .filter(m -> analyzer.requires(m).anyMatch(Analyzer::notFound))
.forEach(m -> {
- analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE);
+ analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE, Analyzer::notFound);
});
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Wed Nov 21 22:33:33 2018 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Wed Nov 21 22:34:01 2018 -0800
@@ -57,6 +57,13 @@
\ name (may be given multiple times). --package,\n\
\ --regex, --require are mutual exclusive.
+main.opt.missing-deps=\
+\ --missing-deps Finds missing dependences. This option\n\
+\ cannot be used with -p, -e and -s options.
+
+main.opt.ignore-missing-deps=\
+\ --ignore-missing-deps Ignore missing dependences.
+
main.opt.include=\n\
\Options to filter classes to be analyzed:\n\
\ -include <regex> Restrict analysis to classes matching pattern\n\
@@ -86,13 +93,18 @@
\ Adds modules to the root set for analysis
main.opt.R=\
-\ -R -recursive Recursively traverse all run-time dependences.\n\
+\ -R\n\
+\ --recursive Recursively traverse all run-time dependences.\n\
\ The -R option implies -filter:none. If -p,\n\
\ -e, -f option is specified, only the matching\n\
\ dependences are analyzed.
+main.opt.no-recursive=\
+\ --no-recursive Do not recursively traverse dependences.
+
main.opt.I=\
-\ -I --inverse Analyzes the dependences per other given options\n\
+\ -I\n\
+\ --inverse Analyzes the dependences per other given options\n\
\ and then find all artifacts that directly\n\
\ and indirectly depend on the matching nodes.\n\
\ This is equivalent to the inverse of\n\
@@ -157,9 +169,11 @@
main.opt.list-deps=\
\ --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.
+\ any internal API packages if referenced.\n\
+\ This option transitively analyzes libraries on\n\
+\ class path and module path if referenced.\n\
+\ Use --no-recursive option for non-transitive\n\
+\ dependency analysis.
main.opt.list-reduced-deps=\
\ --list-reduced-deps Same as --list-deps with not listing\n\
@@ -207,6 +221,10 @@
err.multirelease.option.notfound={0} is a multi-release jar file but --multi-release option is not set
err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2}
err.multirelease.jar.malformed=malformed multi-release jar, {0}, bad entry: {1}
+err.cant.list.module.deps=\
+Missing dependencies from the module path and classpath.\n\
+To suppress this error, use --ignore-missing-deps to continue.
+
warn.invalid.arg=Path does not exist: {0}
warn.skipped.entry={0}
warn.split.package=split package: {0} {1}
--- a/test/langtools/tools/jdeps/Basic.java Wed Nov 21 22:33:33 2018 -0800
+++ b/test/langtools/tools/jdeps/Basic.java Wed Nov 21 22:34:01 2018 -0800
@@ -37,6 +37,7 @@
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.*;
import java.util.regex.*;
import java.util.stream.Collectors;
@@ -135,6 +136,19 @@
new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
new String[] {"compact1", "compact1", dir1.toFile().getName(), dir2.toFile().getName()},
new String[] {"-v", "-classpath", cpath.toString(), "Test.class"});
+
+ // tests --missing-deps option
+ test(new File(testDir, "Test.class"),
+ new String[] {"p.Foo", "p.Bar"},
+ new String[] {"not found", "not found"},
+ new String[] {"--missing-deps"});
+
+ // no missing dependence
+ test(new File(testDir, "Test.class"),
+ new String[0],
+ new String[0],
+ new String[] {"--missing-deps", "-classpath", cpath.toString()});
+
return errors;
}
--- a/test/langtools/tools/jdeps/MultiReleaseJar.java Wed Nov 21 22:33:33 2018 -0800
+++ b/test/langtools/tools/jdeps/MultiReleaseJar.java Wed Nov 21 22:34:01 2018 -0800
@@ -27,7 +27,7 @@
* @summary Tests for jdeps tool with multi-release jar files
* @modules jdk.jdeps/com.sun.tools.jdeps
* @library mrjar mrjar/base mrjar/9 mrjar/10 mrjar/v9 mrjar/v10
- * @build test.* p.* q.* foo/*
+ * @build test.* p.* q.* foo/* Main
* @run testng MultiReleaseJar
*/
@@ -59,10 +59,7 @@
testJdk = System.getProperty("test.jdk");
fileSep = System.getProperty("file.separator");
cmdPath = Paths.get(testJdk, "bin");
- }
- @Test
- public void basic() throws Exception {
// build Version.jar, Version_9.jar and main.jar
Result r = run("jar -cf Version.jar -C base test --release 9 -C 9 test --release 10 -C 10 test");
checkResult(r);
@@ -70,11 +67,20 @@
r = run("jar -cf Version_9.jar -C base test --release 9 -C 9 test");
checkResult(r);
- r = run("jar -cf Main.jar test/Main.class");
+ r = run("jar -cf Main.jar Main.class");
+ checkResult(r);
+
+ r = run("jar -cf Foo.jar -C base p");
checkResult(r);
- // try out a bunch of things
- r = run("jdeps --multi-release 9 -v missing.jar");
+ Path foo = Paths.get(System.getProperty("test.classes")).resolve("modules").resolve("foo");
+ r = run("jar -uf Foo.jar --release 9 -C " + foo.toString() + " module-info.class --release 10 -C v10 q");
+ checkResult(r);
+ }
+
+ @Test
+ public void basic() throws Exception {
+ Result r = run("jdeps --multi-release 9 -v missing.jar");
checkResult(r, false, "Warning: Path does not exist: missing.jar");
r = run("jdeps -v Version.jar");
@@ -115,7 +121,7 @@
r = run("jdeps --multi-release 9.1 -v Version.jar");
checkResult(r, false, "Error: invalid argument for option: 9.1");
- runJdeps("test/Main.class");
+ runJdeps("Main.class");
runJdeps("Main.jar");
}
@@ -124,14 +130,14 @@
Result r = run("jdeps -v -R -cp Version.jar " + path);
checkResult(r, false, "--multi-release option is not set");
- r = run("jdeps -v -R -cp Version.jar -multi-release 9 " + path);
+ r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar -multi-release 9 " + path);
checkResult(r, false,
"Error: unknown option: -multi-release",
"Usage: jdeps <options> <path",
"use --help"
);
- r = run("jdeps -v -R -cp Version.jar --multi-release 9 " + path);
+ r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release 9 " + path);
String name = path;
int index = path.lastIndexOf('/');
@@ -139,66 +145,94 @@
name = path.substring(index + 1, path.length());
}
checkResult(r, true,
- name + " ->",
- name + " ->",
- "test.Main",
- "test.Main",
- "test.Main",
- "Version.jar ->",
+ name + " -> Version.jar",
+ name + " -> foo",
+ name + " -> java.base",
+ "Main",
+ "Main",
+ "Main",
+ "Main",
+ "Version.jar -> java.base",
"9/test.NonPublic",
"9/test.NonPublic",
"9/test.Version",
"9/test.Version",
"9/test.Version",
- "9/test.Version"
+ "9/test.Version",
+ "foo",
+ "Foo.jar",
+ "requires mandated java.base",
+ "foo -> java.base",
+ "p.Foo"
);
- r = run("jdeps -v -R -cp Version.jar --multi-release 10 " + path);
+ r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release 10 " + path);
checkResult(r, true,
- name + " ->",
- name + " ->",
- "test.Main",
- "test.Main",
- "test.Main",
+ name + " -> Version.jar",
+ name + " -> foo",
+ name + " -> java.base",
+ "Main",
+ "Main",
+ "Main",
+ "Main",
"Version.jar ->",
"10/test.Version",
"10/test.Version",
"10/test.Version",
"10/test.Version",
"9/test.NonPublic",
- "9/test.NonPublic"
+ "9/test.NonPublic",
+ "foo",
+ "Foo.jar",
+ "requires mandated java.base",
+ "foo -> java.base",
+ "p.Foo"
);
- r = run("jdeps -v -R -cp Version.jar --multi-release base " + path);
+ r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release base " + path);
checkResult(r, true,
- name + " ->",
- name + " ->",
- "test.Main",
- "test.Main",
- "test.Main",
+ name + " -> Version.jar",
+ name + " -> foo",
+ name + " -> java.base",
+ "Main",
+ "Main",
+ "Main",
+ "Main",
"Version.jar ->",
"test.Version",
- "test.Version"
+ "test.Version",
+ "foo",
+ "Foo.jar",
+ "requires mandated java.base",
+ "foo -> java.base",
+ "p.Foo"
);
- r = run("jdeps -v -R -cp Version.jar --multi-release 9.1 " + path);
+ r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release 9.1 " + path);
checkResult(r, false, "Error: invalid argument for option: 9.1");
// Version_9.jar does not have any version 10 entry
- r = run("jdeps -v -R -cp Version_9.jar --multi-release 10 " + path);
+ r = run("jdeps -v -R -cp Version_9.jar --module-path Foo.jar --multi-release 10 " + path);
checkResult(r, true,
- name + " ->",
- name + " ->",
- "test.Main",
- "test.Main",
- "test.Main",
+ name + " -> Version_9.jar",
+ name + " -> foo",
+ name + " -> java.base",
+ "Main",
+ "Main",
+ "Main",
+ "Main",
"Version_9.jar ->",
"9/test.NonPublic",
"9/test.NonPublic",
"9/test.Version",
"9/test.Version",
"9/test.Version",
- "9/test.Version"
+ "9/test.Version",
+ "foo",
+ "Foo.jar",
+ "requires mandated java.base",
+ "foo -> java.base",
+ "p.Foo"
);
}
@@ -236,17 +270,10 @@
@Test
public void modularJar() throws Exception {
- Result r = run("jar -cf foo.jar -C base p");
- checkResult(r);
-
- Path foo = Paths.get(System.getProperty("test.classes")).resolve("modules").resolve("foo");
- r = run("jar -uf foo.jar --release 9 -C " + foo.toString() + " module-info.class --release 10 -C v10 q");
- checkResult(r);
-
- r = run("jdeps -v --multi-release 10 --module-path foo.jar -m foo");
+ Result r = run("jdeps -v --multi-release 10 --module-path Foo.jar -m foo");
checkResult(r, true,
"foo", // module name
- "foo.jar", // the path to foo.jar
+ "Foo.jar", // the path to Foo.jar
"requires mandated java.base", // module dependences
"foo -> java.base",
"10/q.Bar",
@@ -255,27 +282,24 @@
"p.Foo"
);
- r = run("jdeps --multi-release 9 --module-path foo.jar Main.jar");
+ r = run("jdeps --multi-release 9 -cp Version.jar --module-path Foo.jar Main.jar");
checkResult(r, true,
- "Main.jar ->",
- "test",
- "foo", // module name
- "foo.jar", // the path to foo.jar
- "requires mandated java.base", // module dependences
- "foo -> java.base",
- "p"
+ "Main.jar -> Version.jar",
+ "Main.jar -> foo",
+ "Main.jar -> java.base",
+ "-> java.lang",
+ "-> p",
+ "-> test"
);
- r = run("jdeps --multi-release 10 --module-path foo.jar Main.jar");
+ r = run("jdeps --multi-release 10 -cp Version.jar --module-path Foo.jar Main.jar");
checkResult(r, true,
- "Main.jar ->",
- "test",
- "foo", // module name
- "foo.jar", // the path to foo.jar
- "requires mandated java.base", // module dependences
- "foo -> java.base",
- "p",
- "q"
+ "Main.jar -> Version.jar",
+ "Main.jar -> foo",
+ "Main.jar -> java.base",
+ "-> java.lang",
+ "-> p",
+ "-> test"
);
}
--- a/test/langtools/tools/jdeps/Options.java Wed Nov 21 22:33:33 2018 -0800
+++ b/test/langtools/tools/jdeps/Options.java Wed Nov 21 22:34:01 2018 -0800
@@ -53,7 +53,15 @@
},
{
new String[] { "-jdkinternal", "-p", "java.lang", TEST_CLASSES },
- "--package, --regex, --require cannot be used with -jdkinternals option"
+ "--package, --regex, --require cannot be used with -jdkinternals option"
+ },
+ {
+ new String[] { "--missing-deps", "-summary", TEST_CLASSES },
+ "-summary or -verbose cannot be used with --missing-deps option"
+ },
+ {
+ new String[] { "--missing-deps", "-p", "java.lang", TEST_CLASSES },
+ "--package, --regex, --require cannot be used with --missing-deps option"
},
{
new String[] { "--inverse", TEST_CLASSES },
--- a/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java Wed Nov 21 22:33:33 2018 -0800
+++ b/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java Wed Nov 21 22:34:01 2018 -0800
@@ -35,9 +35,11 @@
* @run testng ListModuleDeps
*/
+import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
+import java.util.List;
import java.util.stream.Collectors;
import org.testng.annotations.BeforeTest;
@@ -53,6 +55,7 @@
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 LIB2_DIR = Paths.get("lib2");
private static final Path HI_CLASS =
CLASSES_DIR.resolve("hi").resolve("Hi.class");
@@ -69,7 +72,8 @@
@BeforeTest
public void compileAll() throws Exception {
// compile library
- assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "lib"), LIB_DIR));
+ assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "lib2"), LIB2_DIR));
+ assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "lib"), LIB_DIR, "-cp", LIB2_DIR.toString()));
// simple program depends only on java.base
assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "hi"), CLASSES_DIR));
@@ -111,7 +115,7 @@
@Test(dataProvider = "listdeps")
public void testListDeps(Path classes, String[] expected) {
JdepsRunner jdeps = JdepsRunner.run(
- "--class-path", LIB_DIR.toString(),
+ "--class-path", LIB_DIR.toString() + File.pathSeparator + LIB2_DIR.toString(),
"--list-deps", classes.toString()
);
String[] output = Arrays.stream(jdeps.output())
@@ -123,7 +127,7 @@
@Test(dataProvider = "reduceddeps")
public void testListReducedDeps(Path classes, String[] expected) {
JdepsRunner jdeps = JdepsRunner.run(
- "--class-path", LIB_DIR.toString(),
+ "--class-path", LIB_DIR.toString() + File.pathSeparator + LIB2_DIR.toString(),
"--list-reduced-deps", classes.toString()
);
String[] output = Arrays.stream(jdeps.output())
@@ -140,6 +144,7 @@
"java.base/jdk.internal.misc",
"java.base/sun.security.util",
"java.logging",
+ "java.management",
"java.sql",
"java.xml/jdk.xml.internal",
"jdk.unsupported"
@@ -154,6 +159,7 @@
{ FOO_CLASS, new String[] {
"java.base",
"java.logging",
+ "java.management",
"java.sql",
"java.xml"
}
@@ -181,6 +187,7 @@
{ CLASSES_DIR, new String[] {
"java.base/jdk.internal.misc",
"java.base/sun.security.util",
+ "java.management",
"java.sql",
"java.xml/jdk.xml.internal",
"jdk.unsupported"
@@ -194,6 +201,7 @@
{ FOO_CLASS, new String[] {
"java.base",
+ "java.management",
"java.sql"
}
},
@@ -215,7 +223,7 @@
@Test(dataProvider = "moduledeps")
public void testPrintModuleDeps(Path classes, String expected) {
JdepsRunner jdeps = JdepsRunner.run(
- "--class-path", LIB_DIR.toString(),
+ "--class-path", LIB_DIR.toString() + File.pathSeparator + LIB2_DIR.toString(),
"--print-module-deps", classes.toString()
);
String output = Arrays.stream(jdeps.output())
@@ -231,6 +239,32 @@
return new Object[][] {
// java.xml is an implied reads edge from java.sql
+ { CLASSES_DIR, "java.base,java.management,java.sql,jdk.unsupported"},
+ { HI_CLASS, "java.base"},
+ { FOO_CLASS, "java.base,java.management,java.sql"},
+ { BAR_CLASS, "java.base,java.xml"},
+ { UNSAFE_CLASS, "java.base,jdk.unsupported"},
+ };
+ }
+
+ @Test(dataProvider = "noRecursiveModuledeps")
+ public void testNoRecursiveModuleDeps(Path classes, String expected) {
+ JdepsRunner jdeps = JdepsRunner.run(
+ "--class-path", LIB_DIR.toString() + File.pathSeparator + LIB2_DIR.toString(),
+ "--print-module-deps", "--no-recursive", classes.toString()
+ );
+ String output = Arrays.stream(jdeps.output())
+ .map(s -> s.trim())
+ .collect(Collectors.joining(","));
+ assertEquals(output, expected);
+ }
+
+ @DataProvider(name = "noRecursiveModuledeps")
+ public Object[][] noRecursiveModuledeps() {
+ 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"},
@@ -238,4 +272,47 @@
{ UNSAFE_CLASS, "java.base,jdk.unsupported"},
};
}
+
+ @DataProvider(name = "recursiveDeps")
+ public Object[][] recursiveDeps() {
+ return new Object[][] {
+ { // lib2 is classpath but not analyzed because lib.Lib is not present
+ // but it is the only class depending on lib2.Lib2
+ List.of("--list-deps", "--class-path", LIB2_DIR.toString(),
+ "--ignore-missing-deps", CLASSES_DIR.toString()),
+ new String[] {
+ "java.base/jdk.internal.misc",
+ "java.base/sun.security.util",
+ "java.logging",
+ "java.sql",
+ "java.xml/jdk.xml.internal",
+ "jdk.unsupported"
+ }
+ },
+ { // lib2 is classpath but not analyzed because lib.Lib is not present
+ // but it is the only class depending on lib2.Lib2
+ List.of("--print-module-deps", "--class-path", LIB2_DIR.toString(),
+ "--ignore-missing-deps", CLASSES_DIR.toString()),
+ new String[] {
+ "java.base,java.sql,jdk.unsupported"
+ }
+ },
+ { // Foo depends on lib.Lib which depends on lib2.Libs
+ List.of("--print-module-deps",
+ "--ignore-missing-deps", FOO_CLASS.toString()),
+ new String[] {
+ "java.base,java.sql"
+ }
+ },
+ };
+ }
+
+ @Test(dataProvider = "recursiveDeps")
+ public void testRecursiveDeps(List<String> options, String[] expected) {
+ JdepsRunner jdeps = JdepsRunner.run(options.toArray(new String[0]));
+ String[] output = Arrays.stream(jdeps.output())
+ .map(s -> s.trim())
+ .toArray(String[]::new);
+ assertEquals(output, expected);
+ }
}
--- a/test/langtools/tools/jdeps/listdeps/src/lib/Lib.java Wed Nov 21 22:33:33 2018 -0800
+++ b/test/langtools/tools/jdeps/listdeps/src/lib/Lib.java Wed Nov 21 22:34:01 2018 -0800
@@ -28,4 +28,5 @@
public class Lib {
public static final String isCoalescing = XMLInputFactory.IS_COALESCING;
public static boolean check() { return true; }
+ public static long getPid() { return lib2.Lib2.getPid(); }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/mrjar/Main.java Wed Nov 21 22:34:01 2018 -0800
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+import test.Version;
+import p.Foo;
+
+public class Main {
+ public void run() {
+ Version v = new Version();
+ v.getVersion();
+ }
+
+ public static void main(String[] args) {
+ (new Main()).run();
+ Foo foo = new Foo();
+ }
+}
--- a/test/langtools/tools/jdeps/mrjar/test/Main.java Wed Nov 21 22:33:33 2018 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * 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 test;
-
-public class Main {
- public void run() {
- Version v = new Version();
- v.getVersion();
- }
-
- public static void main(String[] args) {
- (new Main()).run();
- }
-}