8027481: jdeps to handle classes with the same package name and correct profile for javax.crypto.*
Reviewed-by: alanb, dfuchs
--- a/langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java Mon Oct 28 12:29:34 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java Wed Oct 30 08:35:52 2013 -0700
@@ -26,9 +26,11 @@
import com.sun.tools.classfile.Dependency.Location;
import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
@@ -52,7 +54,7 @@
private final Type type;
private final Map<Archive, ArchiveDeps> results = new HashMap<>();
- private final Map<String, Archive> map = new HashMap<>();
+ private final Map<Location, Archive> map = new HashMap<>();
private final Archive NOT_FOUND
= new Archive(JdepsTask.getMessage("artifact.not.found"));
@@ -69,6 +71,17 @@
* Performs the dependency analysis on the given archives.
*/
public void run(List<Archive> archives) {
+ // build a map from Location to Archive
+ for (Archive archive: archives) {
+ for (Location l: archive.getClasses()) {
+ if (!map.containsKey(l)) {
+ map.put(l, archive);
+ } else {
+ // duplicated class warning?
+ }
+ }
+ }
+ // traverse and analyze all dependencies
for (Archive archive : archives) {
ArchiveDeps deps;
if (type == Type.CLASS || type == Type.VERBOSE) {
@@ -76,33 +89,9 @@
} else {
deps = new PackageVisitor(archive);
}
- archive.visit(deps);
+ archive.visitDependences(deps);
results.put(archive, deps);
}
-
- // set the required dependencies
- for (ArchiveDeps result: results.values()) {
- for (Set<String> set : result.deps.values()) {
- for (String target : set) {
- Archive source = getArchive(target);
- if (result.archive != source) {
- String profile = "";
- if (source instanceof JDKArchive) {
- profile = result.profile != null ? result.profile.toString() : "";
- if (result.getTargetProfile(target) == null) {
- profile += ", JDK internal API";
- // override the value if it accesses any JDK internal
- result.requireArchives.put(source, profile);
- continue;
- }
- }
- if (!result.requireArchives.containsKey(source)) {
- result.requireArchives.put(source, profile);
- }
- }
- }
- }
- }
}
public boolean hasDependences(Archive archive) {
@@ -117,94 +106,143 @@
* Visits the source archive to its destination archive of
* a recorded dependency.
*/
- void visitArchiveDependence(Archive origin, Archive target, String profile);
+ void visitArchiveDependence(Archive origin, Archive target, Profile profile);
/**
* Visits a recorded dependency from origin to target which can be
* a fully-qualified classname, a package name, a profile or
* archive name depending on the Analyzer's type.
*/
- void visitDependence(String origin, Archive source, String target, Archive archive, String profile);
+ void visitDependence(String origin, Archive source, String target, Archive archive, Profile profile);
}
public void visitArchiveDependences(Archive source, Visitor v) {
ArchiveDeps r = results.get(source);
- for (Map.Entry<Archive,String> e : r.requireArchives.entrySet()) {
- v.visitArchiveDependence(r.archive, e.getKey(), e.getValue());
+ for (ArchiveDeps.Dep d: r.requireArchives()) {
+ v.visitArchiveDependence(r.archive, d.archive, d.profile);
}
}
public void visitDependences(Archive source, Visitor v) {
ArchiveDeps r = results.get(source);
- for (String origin : r.deps.keySet()) {
- for (String target : r.deps.get(origin)) {
- Archive archive = getArchive(target);
- assert source == getArchive(origin);
- Profile profile = r.getTargetProfile(target);
-
+ for (Map.Entry<String, SortedSet<ArchiveDeps.Dep>> e: r.deps.entrySet()) {
+ String origin = e.getKey();
+ for (ArchiveDeps.Dep d: e.getValue()) {
// filter intra-dependency unless in verbose mode
- if (type == Type.VERBOSE || archive != source) {
- v.visitDependence(origin, source, target, archive,
- profile != null ? profile.toString() : "");
+ if (type == Type.VERBOSE || d.archive != source) {
+ v.visitDependence(origin, source, d.target, d.archive, d.profile);
}
}
}
}
- public Archive getArchive(String name) {
- return map.containsKey(name) ? map.get(name) : NOT_FOUND;
- }
-
+ /**
+ * ArchiveDeps contains the dependencies for an Archive that
+ * can have one or more classes.
+ */
private abstract class ArchiveDeps implements Archive.Visitor {
final Archive archive;
- final Map<Archive,String> requireArchives;
- final SortedMap<String, SortedSet<String>> deps;
- Profile profile = null;
+ final SortedMap<String, SortedSet<Dep>> deps;
ArchiveDeps(Archive archive) {
this.archive = archive;
- this.requireArchives = new HashMap<>();
this.deps = new TreeMap<>();
}
- void add(String loc) {
- Archive a = map.get(loc);
- if (a == null) {
- map.put(loc, archive);
- } else if (a != archive) {
- // duplicated class warning?
- }
- }
-
- void add(String origin, String target) {
- SortedSet<String> set = deps.get(origin);
+ void add(String origin, String target, Archive targetArchive, String pkgName) {
+ SortedSet<Dep> set = deps.get(origin);
if (set == null) {
deps.put(origin, set = new TreeSet<>());
}
- if (!set.contains(target)) {
- set.add(target);
- // find the corresponding profile
- Profile p = getTargetProfile(target);
- if (profile == null || (p != null && profile.profile < p.profile)) {
- profile = p;
+ Profile p = targetArchive instanceof JDKArchive
+ ? Profile.getProfile(pkgName) : null;
+ set.add(new Dep(target, targetArchive, p));
+ }
+
+ /**
+ * Returns the list of Archive dependences. The returned
+ * list contains one {@code Dep} instance per one archive
+ * and with the minimum profile this archive depends on.
+ */
+ List<Dep> requireArchives() {
+ Map<Archive,Profile> map = new HashMap<>();
+ for (Set<Dep> set: deps.values()) {
+ for (Dep d: set) {
+ if (this.archive != d.archive) {
+ Profile p = map.get(d.archive);
+ if (p == null || (d.profile != null && p.profile < d.profile.profile)) {
+ map.put(d.archive, d.profile);
+ }
+ }
}
}
+ List<Dep> list = new ArrayList<>();
+ for (Map.Entry<Archive,Profile> e: map.entrySet()) {
+ list.add(new Dep("", e.getKey(), e.getValue()));
+ }
+ return list;
+ }
+
+ /**
+ * Dep represents a dependence where the target can be
+ * a classname or packagename and the archive and profile
+ * the target belongs to.
+ */
+ class Dep implements Comparable<Dep> {
+ final String target;
+ final Archive archive;
+ final Profile profile;
+ Dep(String target, Archive archive, Profile p) {
+ this.target = target;
+ this.archive = archive;
+ this.profile = p;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Dep) {
+ Dep d = (Dep)o;
+ return this.archive == d.archive && this.target.equals(d.target);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 17 * hash + Objects.hashCode(this.archive);
+ hash = 17 * hash + Objects.hashCode(this.target);
+ return hash;
+ }
+
+ @Override
+ public int compareTo(Dep o) {
+ if (this.target.equals(o.target)) {
+ if (this.archive == o.archive) {
+ return 0;
+ } else {
+ return this.archive.getFileName().compareTo(o.archive.getFileName());
+ }
+ }
+ return this.target.compareTo(o.target);
+ }
}
public abstract void visit(Location o, Location t);
- public abstract Profile getTargetProfile(String target);
}
private class ClassVisitor extends ArchiveDeps {
ClassVisitor(Archive archive) {
super(archive);
}
- public void visit(Location l) {
- add(l.getClassName());
- }
+ @Override
public void visit(Location o, Location t) {
- add(o.getClassName(), t.getClassName());
- }
- public Profile getTargetProfile(String target) {
- int i = target.lastIndexOf('.');
- return (i > 0) ? Profile.getProfile(target.substring(0, i)) : null;
+ Archive targetArchive =
+ this.archive.getClasses().contains(t) ? this.archive : map.get(t);
+ if (targetArchive == null) {
+ map.put(t, targetArchive = NOT_FOUND);
+ }
+
+ String origin = o.getClassName();
+ String target = t.getClassName();
+ add(origin, target, targetArchive, t.getPackageName());
}
}
@@ -212,18 +250,21 @@
PackageVisitor(Archive archive) {
super(archive);
}
+ @Override
public void visit(Location o, Location t) {
- add(packageOf(o), packageOf(t));
- }
- public void visit(Location l) {
- add(packageOf(l));
+ Archive targetArchive =
+ this.archive.getClasses().contains(t) ? this.archive : map.get(t);
+ if (targetArchive == null) {
+ map.put(t, targetArchive = NOT_FOUND);
+ }
+
+ String origin = packageOf(o);
+ String target = packageOf(t);
+ add(origin, target, targetArchive, t.getPackageName());
}
- private String packageOf(Location loc) {
- String pkg = loc.getPackageName();
+ public String packageOf(Location o) {
+ String pkg = o.getPackageName();
return pkg.isEmpty() ? "<unnamed>" : pkg;
}
- public Profile getTargetProfile(String target) {
- return Profile.getProfile(target);
- }
}
}
--- a/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java Mon Oct 28 12:29:34 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java Wed Oct 30 08:35:52 2013 -0700
@@ -67,6 +67,7 @@
deps.put(origin, set);
}
}
+
public void addClass(Location origin, Location target) {
Set<Location> set = deps.get(origin);
if (set == null) {
@@ -76,21 +77,27 @@
set.add(target);
}
- public void visit(Visitor v) {
+ public Set<Location> getClasses() {
+ return deps.keySet();
+ }
+
+ public void visitDependences(Visitor v) {
for (Map.Entry<Location,Set<Location>> e: deps.entrySet()) {
- v.visit(e.getKey());
for (Location target : e.getValue()) {
v.visit(e.getKey(), target);
}
}
}
+ public String getPathName() {
+ return path != null ? path.toString() : filename;
+ }
+
public String toString() {
- return path != null ? path.toString() : filename;
+ return filename;
}
interface Visitor {
- void visit(Location loc);
void visit(Location origin, Location target);
}
}
--- a/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java Mon Oct 28 12:29:34 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Oct 30 08:35:52 2013 -0700
@@ -190,6 +190,11 @@
task.options.fullVersion = true;
}
},
+ new HiddenOption(false, "-showlabel") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.showLabel = true;
+ }
+ },
new HiddenOption(true, "-depth") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
try {
@@ -279,12 +284,21 @@
private void generateDotFiles(Path dir, Analyzer analyzer) throws IOException {
Path summary = dir.resolve("summary.dot");
- try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary));
- DotFileFormatter formatter = new DotFileFormatter(sw, "summary")) {
- for (Archive archive : sourceLocations) {
- analyzer.visitArchiveDependences(archive, formatter);
+ boolean verbose = options.verbose == Analyzer.Type.VERBOSE;
+ DotGraph<?> graph = verbose ? new DotSummaryForPackage()
+ : new DotSummaryForArchive();
+ for (Archive archive : sourceLocations) {
+ analyzer.visitArchiveDependences(archive, graph);
+ if (verbose || options.showLabel) {
+ // traverse detailed dependences to generate package-level
+ // summary or build labels for edges
+ analyzer.visitDependences(archive, graph);
}
}
+ try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary))) {
+ graph.writeTo(sw);
+ }
+ // output individual .dot file for each archive
if (options.verbose != Analyzer.Type.SUMMARY) {
for (Archive archive : sourceLocations) {
if (analyzer.hasDependences(archive)) {
@@ -365,17 +379,16 @@
}
}
}
+ sourceLocations.addAll(archives);
List<Archive> classpaths = new ArrayList<>(); // for class file lookup
+ classpaths.addAll(getClassPathArchives(options.classpath));
if (options.includePattern != null) {
- archives.addAll(getClassPathArchives(options.classpath));
- } else {
- classpaths.addAll(getClassPathArchives(options.classpath));
+ archives.addAll(classpaths);
}
classpaths.addAll(PlatformClassPath.getArchives());
- // add all archives to the source locations for reporting
- sourceLocations.addAll(archives);
+ // add all classpath archives to the source locations for reporting
sourceLocations.addAll(classpaths);
// Work queue of names of classfiles to be searched.
@@ -557,6 +570,7 @@
boolean showSummary;
boolean wildcard;
boolean apiOnly;
+ boolean showLabel;
String dotOutputDir;
String classpath = "";
int depth = 1;
@@ -627,16 +641,34 @@
return result;
}
+ /**
+ * If the given archive is JDK archive and non-null Profile,
+ * this method returns the profile name only if -profile option is specified;
+ * a null profile indicates it accesses a private JDK API and this method
+ * will return "JDK internal API".
+ *
+ * For non-JDK archives, this method returns the file name of the archive.
+ */
+ private String getProfileArchiveInfo(Archive source, Profile profile) {
+ if (options.showProfile && profile != null)
+ return profile.toString();
+
+ if (source instanceof JDKArchive) {
+ return profile == null ? "JDK internal API (" + source.getFileName() + ")" : "";
+ }
+ return source.getFileName();
+ }
/**
- * Returns the file name of the archive for non-JRE class or
- * internal JRE classes. It returns empty string for SE API.
+ * Returns the profile name or "JDK internal API" for JDK archive;
+ * otherwise empty string.
*/
- private static String getArchiveName(Archive source, String profile) {
- String name = source.getFileName();
- if (source instanceof JDKArchive)
- return profile.isEmpty() ? "JDK internal API (" + name + ")" : "";
- return name;
+ private String profileName(Archive archive, Profile profile) {
+ if (archive instanceof JDKArchive) {
+ return Objects.toString(profile, "JDK internal API");
+ } else {
+ return "";
+ }
}
class RawOutputFormatter implements Analyzer.Visitor {
@@ -648,21 +680,18 @@
private String pkg = "";
@Override
public void visitDependence(String origin, Archive source,
- String target, Archive archive, String profile) {
+ String target, Archive archive, Profile profile) {
if (!origin.equals(pkg)) {
pkg = origin;
writer.format(" %s (%s)%n", origin, source.getFileName());
}
- String name = (options.showProfile && !profile.isEmpty())
- ? profile
- : getArchiveName(archive, profile);
- writer.format(" -> %-50s %s%n", target, name);
+ writer.format(" -> %-50s %s%n", target, getProfileArchiveInfo(archive, profile));
}
@Override
- public void visitArchiveDependence(Archive origin, Archive target, String profile) {
- writer.format("%s -> %s", origin, target);
- if (options.showProfile && !profile.isEmpty()) {
+ public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
+ writer.format("%s -> %s", origin.getPathName(), target.getPathName());
+ if (options.showProfile && profile != null) {
writer.format(" (%s)%n", profile);
} else {
writer.format("%n");
@@ -670,19 +699,14 @@
}
}
- class DotFileFormatter implements Analyzer.Visitor, AutoCloseable {
+ class DotFileFormatter extends DotGraph<String> implements AutoCloseable {
private final PrintWriter writer;
private final String name;
- DotFileFormatter(PrintWriter writer, String name) {
- this.writer = writer;
- this.name = name;
- writer.format("digraph \"%s\" {%n", name);
- }
DotFileFormatter(PrintWriter writer, Archive archive) {
this.writer = writer;
this.name = archive.getFileName();
writer.format("digraph \"%s\" {%n", name);
- writer.format(" // Path: %s%n", archive.toString());
+ writer.format(" // Path: %s%n", archive.getPathName());
}
@Override
@@ -690,39 +714,169 @@
writer.println("}");
}
- private final Set<String> edges = new HashSet<>();
- private String node = "";
@Override
public void visitDependence(String origin, Archive source,
- String target, Archive archive, String profile) {
- if (!node.equals(origin)) {
- edges.clear();
- node = origin;
- }
+ String target, Archive archive, Profile profile) {
// if -P option is specified, package name -> profile will
// be shown and filter out multiple same edges.
- if (!edges.contains(target)) {
- StringBuilder sb = new StringBuilder();
- String name = options.showProfile && !profile.isEmpty()
- ? profile
- : getArchiveName(archive, profile);
- writer.format(" %-50s -> %s;%n",
- String.format("\"%s\"", origin),
- name.isEmpty() ? String.format("\"%s\"", target)
- : String.format("\"%s (%s)\"", target, name));
- edges.add(target);
+ String name = getProfileArchiveInfo(archive, profile);
+ writeEdge(writer, new Edge(origin, target, getProfileArchiveInfo(archive, profile)));
+ }
+ @Override
+ public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ class DotSummaryForArchive extends DotGraph<Archive> {
+ @Override
+ public void visitDependence(String origin, Archive source,
+ String target, Archive archive, Profile profile) {
+ Edge e = findEdge(source, archive);
+ assert e != null;
+ // add the dependency to the label if enabled and not compact1
+ if (profile == Profile.COMPACT1) {
+ return;
+ }
+ e.addLabel(origin, target, profileName(archive, profile));
+ }
+ @Override
+ public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
+ // add an edge with the archive's name with no tag
+ // so that there is only one node for each JDK archive
+ // while there may be edges to different profiles
+ Edge e = addEdge(origin, target, "");
+ if (target instanceof JDKArchive) {
+ // add a label to print the profile
+ if (profile == null) {
+ e.addLabel("JDK internal API");
+ } else if (options.showProfile && !options.showLabel) {
+ e.addLabel(profile.toString());
+ }
}
}
+ }
+ // DotSummaryForPackage generates the summary.dot file for verbose mode
+ // (-v or -verbose option) that includes all class dependencies.
+ // The summary.dot file shows package-level dependencies.
+ class DotSummaryForPackage extends DotGraph<String> {
+ private String packageOf(String cn) {
+ int i = cn.lastIndexOf('.');
+ return i > 0 ? cn.substring(0, i) : "<unnamed>";
+ }
+ @Override
+ public void visitDependence(String origin, Archive source,
+ String target, Archive archive, Profile profile) {
+ // add a package dependency edge
+ String from = packageOf(origin);
+ String to = packageOf(target);
+ Edge e = addEdge(from, to, getProfileArchiveInfo(archive, profile));
+
+ // add the dependency to the label if enabled and not compact1
+ if (!options.showLabel || profile == Profile.COMPACT1) {
+ return;
+ }
+
+ // trim the package name of origin to shorten the label
+ int i = origin.lastIndexOf('.');
+ String n1 = i < 0 ? origin : origin.substring(i+1);
+ e.addLabel(n1, target, profileName(archive, profile));
+ }
@Override
- public void visitArchiveDependence(Archive origin, Archive target, String profile) {
- String name = options.showProfile && !profile.isEmpty()
- ? profile : "";
- writer.format(" %-30s -> \"%s\";%n",
- String.format("\"%s\"", origin.getFileName()),
- name.isEmpty()
- ? target.getFileName()
- : String.format("%s (%s)", target.getFileName(), name));
+ public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
+ // nop
+ }
+ }
+ abstract class DotGraph<T> implements Analyzer.Visitor {
+ private final Set<Edge> edges = new LinkedHashSet<>();
+ private Edge curEdge;
+ public void writeTo(PrintWriter writer) {
+ writer.format("digraph \"summary\" {%n");
+ for (Edge e: edges) {
+ writeEdge(writer, e);
+ }
+ writer.println("}");
+ }
+
+ void writeEdge(PrintWriter writer, Edge e) {
+ writer.format(" %-50s -> \"%s\"%s;%n",
+ String.format("\"%s\"", e.from.toString()),
+ e.tag.isEmpty() ? e.to
+ : String.format("%s (%s)", e.to, e.tag),
+ getLabel(e));
+ }
+
+ Edge addEdge(T origin, T target, String tag) {
+ Edge e = new Edge(origin, target, tag);
+ if (e.equals(curEdge)) {
+ return curEdge;
+ }
+
+ if (edges.contains(e)) {
+ for (Edge e1 : edges) {
+ if (e.equals(e1)) {
+ curEdge = e1;
+ }
+ }
+ } else {
+ edges.add(e);
+ curEdge = e;
+ }
+ return curEdge;
+ }
+
+ Edge findEdge(T origin, T target) {
+ for (Edge e : edges) {
+ if (e.from.equals(origin) && e.to.equals(target)) {
+ return e;
+ }
+ }
+ return null;
+ }
+
+ String getLabel(Edge e) {
+ String label = e.label.toString();
+ return label.isEmpty() ? "" : String.format("[label=\"%s\",fontsize=9]", label);
+ }
+
+ class Edge {
+ final T from;
+ final T to;
+ final String tag; // optional tag
+ final StringBuilder label = new StringBuilder();
+ Edge(T from, T to, String tag) {
+ this.from = from;
+ this.to = to;
+ this.tag = tag;
+ }
+ void addLabel(String s) {
+ label.append(s).append("\\n");
+ }
+ void addLabel(String origin, String target, String profile) {
+ label.append(origin).append(" -> ").append(target);
+ if (!profile.isEmpty()) {
+ label.append(" (" + profile + ")");
+ }
+ label.append("\\n");
+ }
+ @Override @SuppressWarnings("unchecked")
+ public boolean equals(Object o) {
+ if (o instanceof DotGraph<?>.Edge) {
+ DotGraph<?>.Edge e = (DotGraph<?>.Edge)o;
+ return this.from.equals(e.from) &&
+ this.to.equals(e.to) &&
+ this.tag.equals(e.tag);
+ }
+ return false;
+ }
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 67 * hash + Objects.hashCode(this.from) +
+ Objects.hashCode(this.to) + Objects.hashCode(this.tag);
+ return hash;
+ }
}
}
}
--- a/langtools/src/share/classes/com/sun/tools/jdeps/Profile.java Mon Oct 28 12:29:34 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Profile.java Wed Oct 30 08:35:52 2013 -0700
@@ -81,8 +81,12 @@
}
static class PackageToProfile {
+ static String[] JAVAX_CRYPTO_PKGS = new String[] {
+ "javax.crypto",
+ "javax.crypto.interfaces",
+ "javax.crypto.spec"
+ };
static Map<String, Profile> map = initProfiles();
-
private static Map<String, Profile> initProfiles() {
try {
String profilesProps = System.getProperty("jdeps.profiles");
@@ -103,6 +107,9 @@
findProfile(cf);
}
}
+ // special case for javax.crypto.* classes that are not
+ // included in ct.sym since they are in jce.jar
+ Collections.addAll(Profile.COMPACT1.packages, JAVAX_CRYPTO_PKGS);
}
}
} catch (IOException | ConstantPoolException e) {
--- a/langtools/test/tools/jdeps/Basic.java Mon Oct 28 12:29:34 2013 -0700
+++ b/langtools/test/tools/jdeps/Basic.java Wed Oct 30 08:35:52 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -23,9 +23,9 @@
/*
* @test
- * @bug 8003562 8005428 8015912
+ * @bug 8003562 8005428 8015912 8027481
* @summary Basic tests for jdeps tool
- * @build Test p.Foo
+ * @build Test p.Foo p.Bar javax.activity.NotCompactProfile
* @run main Basic
*/
@@ -33,10 +33,12 @@
import java.io.IOException;
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 static java.nio.file.StandardCopyOption.*;
public class Basic {
private static boolean symbolFileExist = initProfiles();
@@ -74,23 +76,25 @@
new String[] {"java.lang", "p"},
new String[] {"compact1", "not found"});
// test a directory
+ // also test non-SE javax.activity class dependency
test(new File(testDir, "p"),
- new String[] {"java.lang", "java.util", "java.lang.management"},
- new String[] {"compact1", "compact1", "compact3"});
+ new String[] {"java.lang", "java.util", "java.lang.management", "javax.activity", "javax.crypto"},
+ new String[] {"compact1", "compact1", "compact3", testDir.getName(), "compact1"},
+ new String[] {"-classpath", testDir.getPath()});
// test class-level dependency output
test(new File(testDir, "Test.class"),
- new String[] {"java.lang.Object", "java.lang.String", "p.Foo"},
- new String[] {"compact1", "compact1", "not found"},
+ new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
+ new String[] {"compact1", "compact1", "not found", "not found"},
new String[] {"-verbose:class"});
// test -p option
test(new File(testDir, "Test.class"),
- new String[] {"p.Foo"},
- new String[] {"not found"},
+ new String[] {"p.Foo", "p.Bar"},
+ new String[] {"not found", "not found"},
new String[] {"-verbose:class", "-p", "p"});
// test -e option
test(new File(testDir, "Test.class"),
- new String[] {"p.Foo"},
- new String[] {"not found"},
+ new String[] {"p.Foo", "p.Bar"},
+ new String[] {"not found", "not found"},
new String[] {"-verbose:class", "-e", "p\\..*"});
test(new File(testDir, "Test.class"),
new String[] {"java.lang"},
@@ -99,13 +103,34 @@
// test -classpath and -include options
test(null,
new String[] {"java.lang", "java.util",
- "java.lang.management"},
- new String[] {"compact1", "compact1", "compact3"},
+ "java.lang.management", "javax.crypto"},
+ new String[] {"compact1", "compact1", "compact3", "compact1"},
new String[] {"-classpath", testDir.getPath(), "-include", "p.+|Test.class"});
test(new File(testDir, "Test.class"),
- new String[] {"java.lang.Object", "java.lang.String", "p.Foo"},
- new String[] {"compact1", "compact1", testDir.getName()},
+ new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
+ new String[] {"compact1", "compact1", testDir.getName(), testDir.getName()},
new String[] {"-v", "-classpath", testDir.getPath(), "Test.class"});
+
+ // split package p - move p/Foo.class to dir1 and p/Bar.class to dir2
+ Path testClassPath = testDir.toPath();
+ Path dirP = testClassPath.resolve("p");
+ Path dir1 = testClassPath.resolve("dir1");
+ Path subdir1P = dir1.resolve("p");
+ Path dir2 = testClassPath.resolve("dir2");
+ Path subdir2P = dir2.resolve("p");
+ if (!Files.exists(subdir1P))
+ Files.createDirectories(subdir1P);
+ if (!Files.exists(subdir2P))
+ Files.createDirectories(subdir2P);
+ Files.move(dirP.resolve("Foo.class"), subdir1P.resolve("Foo.class"), REPLACE_EXISTING);
+ Files.move(dirP.resolve("Bar.class"), subdir2P.resolve("Bar.class"), REPLACE_EXISTING);
+ StringBuilder cpath = new StringBuilder(testDir.toString());
+ cpath.append(File.pathSeparator).append(dir1.toString());
+ cpath.append(File.pathSeparator).append(dir2.toString());
+ test(new File(testDir, "Test.class"),
+ 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"});
return errors;
}
@@ -148,7 +173,7 @@
// Use the linePattern to break the given String into lines, applying
// the pattern to each line to see if we have a match
private static Map<String,String> findDeps(String out) {
- Map<String,String> result = new HashMap<>();
+ Map<String,String> result = new LinkedHashMap<>();
Matcher lm = linePattern.matcher(out); // Line matcher
Matcher pm = null; // Pattern matcher
int lines = 0;
--- a/langtools/test/tools/jdeps/Test.java Mon Oct 28 12:29:34 2013 -0700
+++ b/langtools/test/tools/jdeps/Test.java Wed Oct 30 08:35:52 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -24,6 +24,7 @@
public class Test {
public void test() {
p.Foo f = new p.Foo();
+ p.Bar b = new p.Bar();
}
private String name() {
return "this test";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/javax/activity/NotCompactProfile.java Wed Oct 30 08:35:52 2013 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, 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 javax.activity;
+
+public class NotCompactProfile {
+ public static String name() {
+ return "not Java SE API";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/p/Bar.java Wed Oct 30 08:35:52 2013 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, 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 p;
+
+public class Bar extends javax.activity.NotCompactProfile {
+ public String bar() {
+ return "bar";
+ }
+ public javax.crypto.Cipher getCiper() {
+ return null;
+ }
+}