8213909: jdeps --print-module-deps should report missing dependences
8168869: jdeps: localized messages don't use proper line breaks Reviewed-by: sundar
This commit is contained in:
parent
9d7509e647
commit
0126fdbef0
src/jdk.jdeps/share/classes/com/sun/tools/jdeps
Analyzer.javaDependencyFinder.javaJdepsConfiguration.javaJdepsFilter.javaJdepsTask.javaModule.javaModuleExportsAnalyzer.javaModuleInfoBuilder.java
resources
test/langtools/tools/jdeps
@ -32,6 +32,7 @@ import java.io.IOException;
|
||||
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.HashSet;
|
||||
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 @@ public class Analyzer {
|
||||
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 @@ public class Analyzer {
|
||||
* 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 @@ public class Analyzer {
|
||||
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 @@ public class Analyzer {
|
||||
}
|
||||
|
||||
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 @@ public class Analyzer {
|
||||
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 @@ public class Analyzer {
|
||||
@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 @@ public class Analyzer {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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()
|
||||
@ -393,11 +413,6 @@ public class Analyzer {
|
||||
return jdk8Internals.contains(pn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJDK() {
|
||||
return true;
|
||||
|
@ -38,6 +38,7 @@ import com.sun.tools.classfile.Dependency.Location;
|
||||
|
||||
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 @@ class DependencyFinder {
|
||||
|
||||
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 @@ class DependencyFinder {
|
||||
parsedClasses.putIfAbsent(d.getOrigin(), archive);
|
||||
}
|
||||
}
|
||||
|
||||
return targets;
|
||||
});
|
||||
tasks.add(task);
|
||||
@ -264,8 +264,7 @@ class DependencyFinder {
|
||||
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) {
|
||||
|
@ -83,42 +83,27 @@ public class JdepsConfiguration implements AutoCloseable {
|
||||
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 @@ public class JdepsConfiguration implements AutoCloseable {
|
||||
.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 @@ public class JdepsConfiguration implements AutoCloseable {
|
||||
.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);
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
|
||||
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 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
|
||||
boolean filterSamePackage,
|
||||
boolean filterSameArchive,
|
||||
boolean findJDKInternals,
|
||||
boolean findMissingDeps,
|
||||
Pattern includePattern,
|
||||
Set<String> requires) {
|
||||
this.filter = filter;
|
||||
@ -71,6 +73,7 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
|
||||
this.filterSamePackage = filterSamePackage;
|
||||
this.filterSameArchive = filterSameArchive;
|
||||
this.findJDKInternals = findJDKInternals;
|
||||
this.findMissingDeps = findMissingDeps;
|
||||
this.includePattern = includePattern;
|
||||
this.requires = requires;
|
||||
}
|
||||
@ -153,6 +156,8 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
|
||||
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 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
|
||||
boolean filterSamePackage;
|
||||
boolean filterSameArchive;
|
||||
boolean findJDKInterals;
|
||||
boolean findMissingDeps;
|
||||
// source filters
|
||||
Pattern includePattern;
|
||||
Set<String> requires = new HashSet<>();
|
||||
@ -221,6 +227,10 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
|
||||
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 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
|
||||
filterSamePackage,
|
||||
filterSameArchive,
|
||||
findJDKInterals,
|
||||
findMissingDeps,
|
||||
includePattern,
|
||||
requires);
|
||||
}
|
||||
|
@ -357,6 +357,11 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
}
|
||||
}
|
||||
},
|
||||
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 @@ class JdepsTask {
|
||||
}
|
||||
},
|
||||
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
}
|
||||
|
||||
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 @@ class JdepsTask {
|
||||
|
||||
@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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
|
||||
@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 @@ class JdepsTask {
|
||||
|
||||
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 @@ class JdepsTask {
|
||||
@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 @@ class JdepsTask {
|
||||
|
||||
@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 JdepsTask {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ class JdepsTask {
|
||||
// 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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
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 @@ class JdepsTask {
|
||||
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('.');
|
||||
|
@ -58,12 +58,16 @@ class Module extends Archive {
|
||||
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 @@ class Module extends Archive {
|
||||
}
|
||||
|
||||
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 @@ class Module extends Archive {
|
||||
|
||||
private static class UnnamedModule extends Module {
|
||||
private UnnamedModule() {
|
||||
super("unnamed", null, null,
|
||||
Collections.emptyMap(), Collections.emptyMap(),
|
||||
false, null);
|
||||
super("unnamed", null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -242,16 +244,6 @@ class Module extends Archive {
|
||||
return "unnamed";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNamed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutomatic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExported(String pn) {
|
||||
return true;
|
||||
|
@ -49,42 +49,47 @@ import java.util.stream.Stream;
|
||||
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 @@ public class ModuleExportsAnalyzer extends DepsAnalyzer {
|
||||
.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 @@ public class ModuleExportsAnalyzer extends DepsAnalyzer {
|
||||
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 @@ public class ModuleExportsAnalyzer extends DepsAnalyzer {
|
||||
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 @@ public class ModuleExportsAnalyzer extends DepsAnalyzer {
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,17 +137,13 @@ public class ModuleInfoBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class ModuleInfoBuilder {
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,13 @@ main.opt.require=\
|
||||
\ 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 @@ main.opt.add-modules=\
|
||||
\ 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.jdkinternals=\
|
||||
|
||||
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.exists={0} is not a multi-release jar file but --multi-r
|
||||
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}
|
||||
|
@ -37,6 +37,7 @@ import java.io.PrintWriter;
|
||||
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 @@ public class Basic {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 @@ public class MultiReleaseJar {
|
||||
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 @@ public class MultiReleaseJar {
|
||||
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);
|
||||
|
||||
// try out a bunch of things
|
||||
r = run("jdeps --multi-release 9 -v missing.jar");
|
||||
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);
|
||||
}
|
||||
|
||||
@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 @@ public class MultiReleaseJar {
|
||||
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 @@ public class MultiReleaseJar {
|
||||
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 @@ public class MultiReleaseJar {
|
||||
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 @@ public class MultiReleaseJar {
|
||||
|
||||
@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 @@ public class MultiReleaseJar {
|
||||
"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"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,15 @@ public class Options {
|
||||
},
|
||||
{
|
||||
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 },
|
||||
|
@ -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 @@ public class ListModuleDeps {
|
||||
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 @@ public class ListModuleDeps {
|
||||
@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 @@ public class ListModuleDeps {
|
||||
@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 @@ public class ListModuleDeps {
|
||||
@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 @@ public class ListModuleDeps {
|
||||
"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 @@ public class ListModuleDeps {
|
||||
{ FOO_CLASS, new String[] {
|
||||
"java.base",
|
||||
"java.logging",
|
||||
"java.management",
|
||||
"java.sql",
|
||||
"java.xml"
|
||||
}
|
||||
@ -181,6 +187,7 @@ public class ListModuleDeps {
|
||||
{ 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 @@ public class ListModuleDeps {
|
||||
|
||||
{ FOO_CLASS, new String[] {
|
||||
"java.base",
|
||||
"java.management",
|
||||
"java.sql"
|
||||
}
|
||||
},
|
||||
@ -215,7 +223,7 @@ public class ListModuleDeps {
|
||||
@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())
|
||||
@ -229,6 +237,32 @@ public class ListModuleDeps {
|
||||
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.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"},
|
||||
@ -238,4 +272,47 @@ public class ListModuleDeps {
|
||||
{ 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);
|
||||
}
|
||||
}
|
||||
|
@ -28,4 +28,5 @@ import javax.xml.stream.XMLInputFactory;
|
||||
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(); }
|
||||
}
|
||||
|
@ -21,7 +21,8 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
import test.Version;
|
||||
import p.Foo;
|
||||
|
||||
public class Main {
|
||||
public void run() {
|
||||
@ -31,5 +32,6 @@ public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
(new Main()).run();
|
||||
Foo foo = new Foo();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user