Thu, 17 Oct 2013 13:19:48 -0700
8015912: jdeps support to output in dot file format
8026255: Switch jdeps to follow traditional Java option style
Reviewed-by: alanb
1.1 --- a/src/share/classes/com/sun/tools/jdeps/Analyzer.java Thu Oct 17 13:50:00 2013 +0200 1.2 +++ b/src/share/classes/com/sun/tools/jdeps/Analyzer.java Thu Oct 17 13:19:48 2013 -0700 1.3 @@ -25,9 +25,8 @@ 1.4 package com.sun.tools.jdeps; 1.5 1.6 import com.sun.tools.classfile.Dependency.Location; 1.7 -import java.util.ArrayList; 1.8 +import com.sun.tools.jdeps.PlatformClassPath.JDKArchive; 1.9 import java.util.HashMap; 1.10 -import java.util.HashSet; 1.11 import java.util.List; 1.12 import java.util.Map; 1.13 import java.util.Set; 1.14 @@ -52,8 +51,8 @@ 1.15 }; 1.16 1.17 private final Type type; 1.18 - private final List<ArchiveDeps> results = new ArrayList<ArchiveDeps>(); 1.19 - private final Map<String, Archive> map = new HashMap<String, Archive>(); 1.20 + private final Map<Archive, ArchiveDeps> results = new HashMap<>(); 1.21 + private final Map<String, Archive> map = new HashMap<>(); 1.22 private final Archive NOT_FOUND 1.23 = new Archive(JdepsTask.getMessage("artifact.not.found")); 1.24 1.25 @@ -78,27 +77,27 @@ 1.26 deps = new PackageVisitor(archive); 1.27 } 1.28 archive.visit(deps); 1.29 - results.add(deps); 1.30 + results.put(archive, deps); 1.31 } 1.32 1.33 // set the required dependencies 1.34 - for (ArchiveDeps result: results) { 1.35 + for (ArchiveDeps result: results.values()) { 1.36 for (Set<String> set : result.deps.values()) { 1.37 for (String target : set) { 1.38 Archive source = getArchive(target); 1.39 if (result.archive != source) { 1.40 - if (!result.requiredArchives.contains(source)) { 1.41 - result.requiredArchives.add(source); 1.42 + String profile = ""; 1.43 + if (source instanceof JDKArchive) { 1.44 + profile = result.profile != null ? result.profile.toString() : ""; 1.45 + if (result.getTargetProfile(target) == null) { 1.46 + profile += ", JDK internal API"; 1.47 + // override the value if it accesses any JDK internal 1.48 + result.requireArchives.put(source, profile); 1.49 + continue; 1.50 + } 1.51 } 1.52 - // either a profile name or the archive name 1.53 - String tname = result.getTargetProfile(target); 1.54 - if (tname.isEmpty()) { 1.55 - tname = PlatformClassPath.contains(source) 1.56 - ? "JDK internal API (" + source.getFileName() + ")" 1.57 - : source.toString(); 1.58 - } 1.59 - if (!result.targetNames.contains(tname)) { 1.60 - result.targetNames.add(tname); 1.61 + if (!result.requireArchives.containsKey(source)) { 1.62 + result.requireArchives.put(source, profile); 1.63 } 1.64 } 1.65 } 1.66 @@ -106,42 +105,46 @@ 1.67 } 1.68 } 1.69 1.70 + public boolean hasDependences(Archive archive) { 1.71 + if (results.containsKey(archive)) { 1.72 + return results.get(archive).deps.size() > 0; 1.73 + } 1.74 + return false; 1.75 + } 1.76 + 1.77 public interface Visitor { 1.78 /** 1.79 + * Visits the source archive to its destination archive of 1.80 + * a recorded dependency. 1.81 + */ 1.82 + void visitArchiveDependence(Archive origin, Archive target, String profile); 1.83 + /** 1.84 * Visits a recorded dependency from origin to target which can be 1.85 * a fully-qualified classname, a package name, a profile or 1.86 * archive name depending on the Analyzer's type. 1.87 */ 1.88 - void visit(String origin, String target, String profile); 1.89 - /** 1.90 - * Visits the source archive to its destination archive of 1.91 - * a recorded dependency. 1.92 - */ 1.93 - void visit(Archive source, Archive dest); 1.94 + void visitDependence(String origin, Archive source, String target, Archive archive, String profile); 1.95 } 1.96 1.97 - public void visitSummary(Visitor v) { 1.98 - for (ArchiveDeps r : results) { 1.99 - for (Archive a : r.requiredArchives) { 1.100 - v.visit(r.archive, a); 1.101 - } 1.102 - for (String name : r.targetNames) { 1.103 - v.visit(r.archive.getFileName(), name, name); 1.104 - } 1.105 + public void visitArchiveDependences(Archive source, Visitor v) { 1.106 + ArchiveDeps r = results.get(source); 1.107 + for (Map.Entry<Archive,String> e : r.requireArchives.entrySet()) { 1.108 + v.visitArchiveDependence(r.archive, e.getKey(), e.getValue()); 1.109 } 1.110 } 1.111 1.112 - public void visit(Visitor v) { 1.113 - for (ArchiveDeps r: results) { 1.114 - for (Archive a : r.requiredArchives) { 1.115 - v.visit(r.archive, a); 1.116 - } 1.117 - for (String origin : r.deps.keySet()) { 1.118 - for (String target : r.deps.get(origin)) { 1.119 - // filter intra-dependency unless in verbose mode 1.120 - if (type == Type.VERBOSE || getArchive(origin) != getArchive(target)) { 1.121 - v.visit(origin, target, r.getTargetProfile(target)); 1.122 - } 1.123 + public void visitDependences(Archive source, Visitor v) { 1.124 + ArchiveDeps r = results.get(source); 1.125 + for (String origin : r.deps.keySet()) { 1.126 + for (String target : r.deps.get(origin)) { 1.127 + Archive archive = getArchive(target); 1.128 + assert source == getArchive(origin); 1.129 + Profile profile = r.getTargetProfile(target); 1.130 + 1.131 + // filter intra-dependency unless in verbose mode 1.132 + if (type == Type.VERBOSE || archive != source) { 1.133 + v.visitDependence(origin, source, target, archive, 1.134 + profile != null ? profile.toString() : ""); 1.135 } 1.136 } 1.137 } 1.138 @@ -151,29 +154,15 @@ 1.139 return map.containsKey(name) ? map.get(name) : NOT_FOUND; 1.140 } 1.141 1.142 - /** 1.143 - * Returns the file name of the archive for non-JRE class or 1.144 - * internal JRE classes. It returns empty string for SE API. 1.145 - */ 1.146 - public String getArchiveName(String target, String profile) { 1.147 - Archive source = getArchive(target); 1.148 - String name = source.getFileName(); 1.149 - if (PlatformClassPath.contains(source)) 1.150 - return profile.isEmpty() ? "JDK internal API (" + name + ")" : ""; 1.151 - return name; 1.152 - } 1.153 - 1.154 private abstract class ArchiveDeps implements Archive.Visitor { 1.155 final Archive archive; 1.156 - final Set<Archive> requiredArchives; 1.157 - final SortedSet<String> targetNames; 1.158 + final Map<Archive,String> requireArchives; 1.159 final SortedMap<String, SortedSet<String>> deps; 1.160 - 1.161 + Profile profile = null; 1.162 ArchiveDeps(Archive archive) { 1.163 this.archive = archive; 1.164 - this.requiredArchives = new HashSet<Archive>(); 1.165 - this.targetNames = new TreeSet<String>(); 1.166 - this.deps = new TreeMap<String, SortedSet<String>>(); 1.167 + this.requireArchives = new HashMap<>(); 1.168 + this.deps = new TreeMap<>(); 1.169 } 1.170 1.171 void add(String loc) { 1.172 @@ -188,17 +177,19 @@ 1.173 void add(String origin, String target) { 1.174 SortedSet<String> set = deps.get(origin); 1.175 if (set == null) { 1.176 - set = new TreeSet<String>(); 1.177 - deps.put(origin, set); 1.178 + deps.put(origin, set = new TreeSet<>()); 1.179 } 1.180 if (!set.contains(target)) { 1.181 set.add(target); 1.182 + // find the corresponding profile 1.183 + Profile p = getTargetProfile(target); 1.184 + if (profile == null || (p != null && profile.profile < p.profile)) { 1.185 + profile = p; 1.186 + } 1.187 } 1.188 } 1.189 - 1.190 public abstract void visit(Location o, Location t); 1.191 - public abstract String getTargetProfile(String target); 1.192 - 1.193 + public abstract Profile getTargetProfile(String target); 1.194 } 1.195 1.196 private class ClassVisitor extends ArchiveDeps { 1.197 @@ -211,9 +202,9 @@ 1.198 public void visit(Location o, Location t) { 1.199 add(o.getClassName(), t.getClassName()); 1.200 } 1.201 - public String getTargetProfile(String target) { 1.202 + public Profile getTargetProfile(String target) { 1.203 int i = target.lastIndexOf('.'); 1.204 - return (i > 0) ? Profiles.getProfileName(target.substring(0, i)) : ""; 1.205 + return (i > 0) ? Profile.getProfile(target.substring(0, i)) : null; 1.206 } 1.207 } 1.208 1.209 @@ -231,8 +222,8 @@ 1.210 String pkg = loc.getPackageName(); 1.211 return pkg.isEmpty() ? "<unnamed>" : pkg; 1.212 } 1.213 - public String getTargetProfile(String target) { 1.214 - return Profiles.getProfileName(target); 1.215 + public Profile getTargetProfile(String target) { 1.216 + return Profile.getProfile(target); 1.217 } 1.218 } 1.219 }
2.1 --- a/src/share/classes/com/sun/tools/jdeps/Archive.java Thu Oct 17 13:50:00 2013 +0200 2.2 +++ b/src/share/classes/com/sun/tools/jdeps/Archive.java Thu Oct 17 13:19:48 2013 -0700 2.3 @@ -25,7 +25,7 @@ 2.4 package com.sun.tools.jdeps; 2.5 2.6 import com.sun.tools.classfile.Dependency.Location; 2.7 -import java.io.File; 2.8 +import java.nio.file.Path; 2.9 import java.util.HashMap; 2.10 import java.util.HashSet; 2.11 import java.util.Map; 2.12 @@ -35,21 +35,20 @@ 2.13 * Represents the source of the class files. 2.14 */ 2.15 public class Archive { 2.16 - private final File file; 2.17 + private final Path path; 2.18 private final String filename; 2.19 private final ClassFileReader reader; 2.20 - private final Map<Location, Set<Location>> deps 2.21 - = new HashMap<Location, Set<Location>>(); 2.22 + private final Map<Location, Set<Location>> deps = new HashMap<>(); 2.23 2.24 public Archive(String name) { 2.25 - this.file = null; 2.26 + this.path = null; 2.27 this.filename = name; 2.28 this.reader = null; 2.29 } 2.30 2.31 - public Archive(File f, ClassFileReader reader) { 2.32 - this.file = f; 2.33 - this.filename = f.getName(); 2.34 + public Archive(Path p, ClassFileReader reader) { 2.35 + this.path = p; 2.36 + this.filename = path.getFileName().toString(); 2.37 this.reader = reader; 2.38 } 2.39 2.40 @@ -64,14 +63,14 @@ 2.41 public void addClass(Location origin) { 2.42 Set<Location> set = deps.get(origin); 2.43 if (set == null) { 2.44 - set = new HashSet<Location>(); 2.45 + set = new HashSet<>(); 2.46 deps.put(origin, set); 2.47 } 2.48 } 2.49 public void addClass(Location origin, Location target) { 2.50 Set<Location> set = deps.get(origin); 2.51 if (set == null) { 2.52 - set = new HashSet<Location>(); 2.53 + set = new HashSet<>(); 2.54 deps.put(origin, set); 2.55 } 2.56 set.add(target); 2.57 @@ -87,7 +86,7 @@ 2.58 } 2.59 2.60 public String toString() { 2.61 - return file != null ? file.getPath() : filename; 2.62 + return path != null ? path.toString() : filename; 2.63 } 2.64 2.65 interface Visitor {
3.1 --- a/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java Thu Oct 17 13:50:00 2013 +0200 3.2 +++ b/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java Thu Oct 17 13:19:48 2013 -0700 3.3 @@ -45,17 +45,17 @@ 3.4 /** 3.5 * Returns a ClassFileReader instance of a given path. 3.6 */ 3.7 - public static ClassFileReader newInstance(File path) throws IOException { 3.8 - if (!path.exists()) { 3.9 - throw new FileNotFoundException(path.getAbsolutePath()); 3.10 + public static ClassFileReader newInstance(Path path) throws IOException { 3.11 + if (!Files.exists(path)) { 3.12 + throw new FileNotFoundException(path.toString()); 3.13 } 3.14 3.15 - if (path.isDirectory()) { 3.16 - return new DirectoryReader(path.toPath()); 3.17 - } else if (path.getName().endsWith(".jar")) { 3.18 - return new JarFileReader(path.toPath()); 3.19 + if (Files.isDirectory(path)) { 3.20 + return new DirectoryReader(path); 3.21 + } else if (path.getFileName().toString().endsWith(".jar")) { 3.22 + return new JarFileReader(path); 3.23 } else { 3.24 - return new ClassFileReader(path.toPath()); 3.25 + return new ClassFileReader(path); 3.26 } 3.27 } 3.28 3.29 @@ -163,16 +163,16 @@ 3.30 int i = name.lastIndexOf('.'); 3.31 String pathname = name.replace('.', File.separatorChar) + ".class"; 3.32 Path p = path.resolve(pathname); 3.33 - if (!p.toFile().exists()) { 3.34 + if (!Files.exists(p)) { 3.35 p = path.resolve(pathname.substring(0, i) + "$" + 3.36 pathname.substring(i+1, pathname.length())); 3.37 } 3.38 - if (p.toFile().exists()) { 3.39 + if (Files.exists(p)) { 3.40 return readClassFile(p); 3.41 } 3.42 } else { 3.43 Path p = path.resolve(name + ".class"); 3.44 - if (p.toFile().exists()) { 3.45 + if (Files.exists(p)) { 3.46 return readClassFile(p); 3.47 } 3.48 } 3.49 @@ -193,7 +193,7 @@ 3.50 Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { 3.51 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 3.52 throws IOException { 3.53 - if (file.toFile().getName().endsWith(".class")) { 3.54 + if (file.getFileName().toString().endsWith(".class")) { 3.55 files.add(file); 3.56 } 3.57 return FileVisitResult.CONTINUE;
4.1 --- a/src/share/classes/com/sun/tools/jdeps/JdepsTask.java Thu Oct 17 13:50:00 2013 +0200 4.2 +++ b/src/share/classes/com/sun/tools/jdeps/JdepsTask.java Thu Oct 17 13:19:48 2013 -0700 4.3 @@ -24,12 +24,18 @@ 4.4 */ 4.5 package com.sun.tools.jdeps; 4.6 4.7 +import com.sun.tools.classfile.AccessFlags; 4.8 import com.sun.tools.classfile.ClassFile; 4.9 import com.sun.tools.classfile.ConstantPoolException; 4.10 import com.sun.tools.classfile.Dependencies; 4.11 import com.sun.tools.classfile.Dependencies.ClassFileError; 4.12 import com.sun.tools.classfile.Dependency; 4.13 +import com.sun.tools.jdeps.PlatformClassPath.JDKArchive; 4.14 import java.io.*; 4.15 +import java.nio.file.DirectoryStream; 4.16 +import java.nio.file.Files; 4.17 +import java.nio.file.Path; 4.18 +import java.nio.file.Paths; 4.19 import java.text.MessageFormat; 4.20 import java.util.*; 4.21 import java.util.regex.Pattern; 4.22 @@ -67,11 +73,10 @@ 4.23 4.24 boolean matches(String opt) { 4.25 for (String a : aliases) { 4.26 - if (a.equals(opt)) { 4.27 + if (a.equals(opt)) 4.28 return true; 4.29 - } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { 4.30 + if (hasArg && opt.startsWith(a + "=")) 4.31 return true; 4.32 - } 4.33 } 4.34 return false; 4.35 } 4.36 @@ -96,62 +101,96 @@ 4.37 } 4.38 4.39 static Option[] recognizedOptions = { 4.40 - new Option(false, "-h", "-?", "--help") { 4.41 + new Option(false, "-h", "-?", "-help") { 4.42 void process(JdepsTask task, String opt, String arg) { 4.43 task.options.help = true; 4.44 } 4.45 }, 4.46 - new Option(false, "-s", "--summary") { 4.47 + new Option(true, "-dotoutput") { 4.48 + void process(JdepsTask task, String opt, String arg) throws BadArgs { 4.49 + Path p = Paths.get(arg); 4.50 + if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) { 4.51 + throw new BadArgs("err.dot.output.path", arg); 4.52 + } 4.53 + task.options.dotOutputDir = arg; 4.54 + } 4.55 + }, 4.56 + new Option(false, "-s", "-summary") { 4.57 void process(JdepsTask task, String opt, String arg) { 4.58 task.options.showSummary = true; 4.59 task.options.verbose = Analyzer.Type.SUMMARY; 4.60 } 4.61 }, 4.62 - new Option(false, "-v", "--verbose") { 4.63 - void process(JdepsTask task, String opt, String arg) { 4.64 - task.options.verbose = Analyzer.Type.VERBOSE; 4.65 - } 4.66 - }, 4.67 - new Option(true, "-V", "--verbose-level") { 4.68 + new Option(false, "-v", "-verbose", 4.69 + "-verbose:package", 4.70 + "-verbose:class") 4.71 + { 4.72 void process(JdepsTask task, String opt, String arg) throws BadArgs { 4.73 - if ("package".equals(arg)) { 4.74 - task.options.verbose = Analyzer.Type.PACKAGE; 4.75 - } else if ("class".equals(arg)) { 4.76 - task.options.verbose = Analyzer.Type.CLASS; 4.77 - } else { 4.78 - throw new BadArgs("err.invalid.arg.for.option", opt); 4.79 + switch (opt) { 4.80 + case "-v": 4.81 + case "-verbose": 4.82 + task.options.verbose = Analyzer.Type.VERBOSE; 4.83 + break; 4.84 + case "-verbose:package": 4.85 + task.options.verbose = Analyzer.Type.PACKAGE; 4.86 + break; 4.87 + case "-verbose:class": 4.88 + task.options.verbose = Analyzer.Type.CLASS; 4.89 + break; 4.90 + default: 4.91 + throw new BadArgs("err.invalid.arg.for.option", opt); 4.92 } 4.93 } 4.94 }, 4.95 - new Option(true, "-c", "--classpath") { 4.96 + new Option(true, "-cp", "-classpath") { 4.97 void process(JdepsTask task, String opt, String arg) { 4.98 task.options.classpath = arg; 4.99 } 4.100 }, 4.101 - new Option(true, "-p", "--package") { 4.102 + new Option(true, "-p", "-package") { 4.103 void process(JdepsTask task, String opt, String arg) { 4.104 task.options.packageNames.add(arg); 4.105 } 4.106 }, 4.107 - new Option(true, "-e", "--regex") { 4.108 + new Option(true, "-e", "-regex") { 4.109 void process(JdepsTask task, String opt, String arg) { 4.110 task.options.regex = arg; 4.111 } 4.112 }, 4.113 - new Option(false, "-P", "--profile") { 4.114 + new Option(true, "-include") { 4.115 + void process(JdepsTask task, String opt, String arg) throws BadArgs { 4.116 + task.options.includePattern = Pattern.compile(arg); 4.117 + } 4.118 + }, 4.119 + new Option(false, "-P", "-profile") { 4.120 void process(JdepsTask task, String opt, String arg) throws BadArgs { 4.121 task.options.showProfile = true; 4.122 - if (Profiles.getProfileCount() == 0) { 4.123 + if (Profile.getProfileCount() == 0) { 4.124 throw new BadArgs("err.option.unsupported", opt, getMessage("err.profiles.msg")); 4.125 } 4.126 } 4.127 }, 4.128 - new Option(false, "-R", "--recursive") { 4.129 + new Option(false, "-apionly") { 4.130 + void process(JdepsTask task, String opt, String arg) { 4.131 + task.options.apiOnly = true; 4.132 + } 4.133 + }, 4.134 + new Option(false, "-R", "-recursive") { 4.135 void process(JdepsTask task, String opt, String arg) { 4.136 task.options.depth = 0; 4.137 } 4.138 }, 4.139 - new HiddenOption(true, "-d", "--depth") { 4.140 + new Option(false, "-version") { 4.141 + void process(JdepsTask task, String opt, String arg) { 4.142 + task.options.version = true; 4.143 + } 4.144 + }, 4.145 + new HiddenOption(false, "-fullversion") { 4.146 + void process(JdepsTask task, String opt, String arg) { 4.147 + task.options.fullVersion = true; 4.148 + } 4.149 + }, 4.150 + new HiddenOption(true, "-depth") { 4.151 void process(JdepsTask task, String opt, String arg) throws BadArgs { 4.152 try { 4.153 task.options.depth = Integer.parseInt(arg); 4.154 @@ -160,16 +199,6 @@ 4.155 } 4.156 } 4.157 }, 4.158 - new Option(false, "--version") { 4.159 - void process(JdepsTask task, String opt, String arg) { 4.160 - task.options.version = true; 4.161 - } 4.162 - }, 4.163 - new HiddenOption(false, "--fullversion") { 4.164 - void process(JdepsTask task, String opt, String arg) { 4.165 - task.options.fullVersion = true; 4.166 - } 4.167 - }, 4.168 }; 4.169 4.170 private static final String PROGNAME = "jdeps"; 4.171 @@ -202,7 +231,7 @@ 4.172 if (options.version || options.fullVersion) { 4.173 showVersion(options.fullVersion); 4.174 } 4.175 - if (classes.isEmpty() && !options.wildcard) { 4.176 + if (classes.isEmpty() && options.includePattern == null) { 4.177 if (options.help || options.version || options.fullVersion) { 4.178 return EXIT_OK; 4.179 } else { 4.180 @@ -233,19 +262,51 @@ 4.181 } 4.182 } 4.183 4.184 - private final List<Archive> sourceLocations = new ArrayList<Archive>(); 4.185 + private final List<Archive> sourceLocations = new ArrayList<>(); 4.186 private boolean run() throws IOException { 4.187 findDependencies(); 4.188 Analyzer analyzer = new Analyzer(options.verbose); 4.189 analyzer.run(sourceLocations); 4.190 - if (options.verbose == Analyzer.Type.SUMMARY) { 4.191 - printSummary(log, analyzer); 4.192 + if (options.dotOutputDir != null) { 4.193 + Path dir = Paths.get(options.dotOutputDir); 4.194 + Files.createDirectories(dir); 4.195 + generateDotFiles(dir, analyzer); 4.196 } else { 4.197 - printDependencies(log, analyzer); 4.198 + printRawOutput(log, analyzer); 4.199 } 4.200 return true; 4.201 } 4.202 4.203 + private void generateDotFiles(Path dir, Analyzer analyzer) throws IOException { 4.204 + Path summary = dir.resolve("summary.dot"); 4.205 + try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary)); 4.206 + DotFileFormatter formatter = new DotFileFormatter(sw, "summary")) { 4.207 + for (Archive archive : sourceLocations) { 4.208 + analyzer.visitArchiveDependences(archive, formatter); 4.209 + } 4.210 + } 4.211 + if (options.verbose != Analyzer.Type.SUMMARY) { 4.212 + for (Archive archive : sourceLocations) { 4.213 + if (analyzer.hasDependences(archive)) { 4.214 + Path dotfile = dir.resolve(archive.getFileName() + ".dot"); 4.215 + try (PrintWriter pw = new PrintWriter(Files.newOutputStream(dotfile)); 4.216 + DotFileFormatter formatter = new DotFileFormatter(pw, archive)) { 4.217 + analyzer.visitDependences(archive, formatter); 4.218 + } 4.219 + } 4.220 + } 4.221 + } 4.222 + } 4.223 + 4.224 + private void printRawOutput(PrintWriter writer, Analyzer analyzer) { 4.225 + for (Archive archive : sourceLocations) { 4.226 + RawOutputFormatter formatter = new RawOutputFormatter(writer); 4.227 + analyzer.visitArchiveDependences(archive, formatter); 4.228 + if (options.verbose != Analyzer.Type.SUMMARY) { 4.229 + analyzer.visitDependences(archive, formatter); 4.230 + } 4.231 + } 4.232 + } 4.233 private boolean isValidClassName(String name) { 4.234 if (!Character.isJavaIdentifierStart(name.charAt(0))) { 4.235 return false; 4.236 @@ -259,27 +320,43 @@ 4.237 return true; 4.238 } 4.239 4.240 - private void findDependencies() throws IOException { 4.241 - Dependency.Finder finder = Dependencies.getClassDependencyFinder(); 4.242 - Dependency.Filter filter; 4.243 - if (options.regex != null) { 4.244 - filter = Dependencies.getRegexFilter(Pattern.compile(options.regex)); 4.245 + private Dependency.Filter getDependencyFilter() { 4.246 + if (options.regex != null) { 4.247 + return Dependencies.getRegexFilter(Pattern.compile(options.regex)); 4.248 } else if (options.packageNames.size() > 0) { 4.249 - filter = Dependencies.getPackageFilter(options.packageNames, false); 4.250 + return Dependencies.getPackageFilter(options.packageNames, false); 4.251 } else { 4.252 - filter = new Dependency.Filter() { 4.253 + return new Dependency.Filter() { 4.254 + @Override 4.255 public boolean accepts(Dependency dependency) { 4.256 return !dependency.getOrigin().equals(dependency.getTarget()); 4.257 } 4.258 }; 4.259 } 4.260 + } 4.261 4.262 - List<Archive> archives = new ArrayList<Archive>(); 4.263 - Deque<String> roots = new LinkedList<String>(); 4.264 + private boolean matches(String classname, AccessFlags flags) { 4.265 + if (options.apiOnly && !flags.is(AccessFlags.ACC_PUBLIC)) { 4.266 + return false; 4.267 + } else if (options.includePattern != null) { 4.268 + return options.includePattern.matcher(classname.replace('/', '.')).matches(); 4.269 + } else { 4.270 + return true; 4.271 + } 4.272 + } 4.273 + 4.274 + private void findDependencies() throws IOException { 4.275 + Dependency.Finder finder = 4.276 + options.apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED) 4.277 + : Dependencies.getClassDependencyFinder(); 4.278 + Dependency.Filter filter = getDependencyFilter(); 4.279 + 4.280 + List<Archive> archives = new ArrayList<>(); 4.281 + Deque<String> roots = new LinkedList<>(); 4.282 for (String s : classes) { 4.283 - File f = new File(s); 4.284 - if (f.exists()) { 4.285 - archives.add(new Archive(f, ClassFileReader.newInstance(f))); 4.286 + Path p = Paths.get(s); 4.287 + if (Files.exists(p)) { 4.288 + archives.add(new Archive(p, ClassFileReader.newInstance(p))); 4.289 } else { 4.290 if (isValidClassName(s)) { 4.291 roots.add(s); 4.292 @@ -289,9 +366,8 @@ 4.293 } 4.294 } 4.295 4.296 - List<Archive> classpaths = new ArrayList<Archive>(); // for class file lookup 4.297 - if (options.wildcard) { 4.298 - // include all archives from classpath to the initial list 4.299 + List<Archive> classpaths = new ArrayList<>(); // for class file lookup 4.300 + if (options.includePattern != null) { 4.301 archives.addAll(getClassPathArchives(options.classpath)); 4.302 } else { 4.303 classpaths.addAll(getClassPathArchives(options.classpath)); 4.304 @@ -305,8 +381,8 @@ 4.305 // Work queue of names of classfiles to be searched. 4.306 // Entries will be unique, and for classes that do not yet have 4.307 // dependencies in the results map. 4.308 - Deque<String> deque = new LinkedList<String>(); 4.309 - Set<String> doneClasses = new HashSet<String>(); 4.310 + Deque<String> deque = new LinkedList<>(); 4.311 + Set<String> doneClasses = new HashSet<>(); 4.312 4.313 // get the immediate dependencies of the input files 4.314 for (Archive a : archives) { 4.315 @@ -318,16 +394,18 @@ 4.316 throw new ClassFileError(e); 4.317 } 4.318 4.319 - if (!doneClasses.contains(classFileName)) { 4.320 - doneClasses.add(classFileName); 4.321 - } 4.322 - for (Dependency d : finder.findDependencies(cf)) { 4.323 - if (filter.accepts(d)) { 4.324 - String cn = d.getTarget().getName(); 4.325 - if (!doneClasses.contains(cn) && !deque.contains(cn)) { 4.326 - deque.add(cn); 4.327 + if (matches(classFileName, cf.access_flags)) { 4.328 + if (!doneClasses.contains(classFileName)) { 4.329 + doneClasses.add(classFileName); 4.330 + } 4.331 + for (Dependency d : finder.findDependencies(cf)) { 4.332 + if (filter.accepts(d)) { 4.333 + String cn = d.getTarget().getName(); 4.334 + if (!doneClasses.contains(cn) && !deque.contains(cn)) { 4.335 + deque.add(cn); 4.336 + } 4.337 + a.addClass(d.getOrigin(), d.getTarget()); 4.338 } 4.339 - a.addClass(d.getOrigin(), d.getTarget()); 4.340 } 4.341 } 4.342 } 4.343 @@ -379,46 +457,10 @@ 4.344 } 4.345 } 4.346 unresolved = deque; 4.347 - deque = new LinkedList<String>(); 4.348 + deque = new LinkedList<>(); 4.349 } while (!unresolved.isEmpty() && depth-- > 0); 4.350 } 4.351 4.352 - private void printSummary(final PrintWriter out, final Analyzer analyzer) { 4.353 - Analyzer.Visitor visitor = new Analyzer.Visitor() { 4.354 - public void visit(String origin, String target, String profile) { 4.355 - if (options.showProfile) { 4.356 - out.format("%-30s -> %s%n", origin, target); 4.357 - } 4.358 - } 4.359 - public void visit(Archive origin, Archive target) { 4.360 - if (!options.showProfile) { 4.361 - out.format("%-30s -> %s%n", origin, target); 4.362 - } 4.363 - } 4.364 - }; 4.365 - analyzer.visitSummary(visitor); 4.366 - } 4.367 - 4.368 - private void printDependencies(final PrintWriter out, final Analyzer analyzer) { 4.369 - Analyzer.Visitor visitor = new Analyzer.Visitor() { 4.370 - private String pkg = ""; 4.371 - public void visit(String origin, String target, String profile) { 4.372 - if (!origin.equals(pkg)) { 4.373 - pkg = origin; 4.374 - out.format(" %s (%s)%n", origin, analyzer.getArchive(origin).getFileName()); 4.375 - } 4.376 - out.format(" -> %-50s %s%n", target, 4.377 - (options.showProfile && !profile.isEmpty()) 4.378 - ? profile 4.379 - : analyzer.getArchiveName(target, profile)); 4.380 - } 4.381 - public void visit(Archive origin, Archive target) { 4.382 - out.format("%s -> %s%n", origin, target); 4.383 - } 4.384 - }; 4.385 - analyzer.visit(visitor); 4.386 - } 4.387 - 4.388 public void handleOptions(String[] args) throws BadArgs { 4.389 // process options 4.390 for (int i=0; i < args.length; i++) { 4.391 @@ -427,7 +469,7 @@ 4.392 Option option = getOption(name); 4.393 String param = null; 4.394 if (option.hasArg) { 4.395 - if (name.startsWith("--") && name.indexOf('=') > 0) { 4.396 + if (name.startsWith("-") && name.indexOf('=') > 0) { 4.397 param = name.substring(name.indexOf('=') + 1, name.length()); 4.398 } else if (i + 1 < args.length) { 4.399 param = args[++i]; 4.400 @@ -447,11 +489,7 @@ 4.401 if (name.charAt(0) == '-') { 4.402 throw new BadArgs("err.option.after.class", name).showUsage(true); 4.403 } 4.404 - if (name.equals("*") || name.equals("\"*\"")) { 4.405 - options.wildcard = true; 4.406 - } else { 4.407 - classes.add(name); 4.408 - } 4.409 + classes.add(name); 4.410 } 4.411 } 4.412 } 4.413 @@ -518,13 +556,15 @@ 4.414 boolean showProfile; 4.415 boolean showSummary; 4.416 boolean wildcard; 4.417 - String regex; 4.418 + boolean apiOnly; 4.419 + String dotOutputDir; 4.420 String classpath = ""; 4.421 int depth = 1; 4.422 Analyzer.Type verbose = Analyzer.Type.PACKAGE; 4.423 - Set<String> packageNames = new HashSet<String>(); 4.424 + Set<String> packageNames = new HashSet<>(); 4.425 + String regex; // apply to the dependences 4.426 + Pattern includePattern; // apply to classes 4.427 } 4.428 - 4.429 private static class ResourceBundleHelper { 4.430 static final ResourceBundle versionRB; 4.431 static final ResourceBundle bundle; 4.432 @@ -547,9 +587,9 @@ 4.433 private List<Archive> getArchives(List<String> filenames) throws IOException { 4.434 List<Archive> result = new ArrayList<Archive>(); 4.435 for (String s : filenames) { 4.436 - File f = new File(s); 4.437 - if (f.exists()) { 4.438 - result.add(new Archive(f, ClassFileReader.newInstance(f))); 4.439 + Path p = Paths.get(s); 4.440 + if (Files.exists(p)) { 4.441 + result.add(new Archive(p, ClassFileReader.newInstance(p))); 4.442 } else { 4.443 warning("warn.file.not.exist", s); 4.444 } 4.445 @@ -558,18 +598,131 @@ 4.446 } 4.447 4.448 private List<Archive> getClassPathArchives(String paths) throws IOException { 4.449 - List<Archive> result = new ArrayList<Archive>(); 4.450 + List<Archive> result = new ArrayList<>(); 4.451 if (paths.isEmpty()) { 4.452 return result; 4.453 } 4.454 for (String p : paths.split(File.pathSeparator)) { 4.455 if (p.length() > 0) { 4.456 - File f = new File(p); 4.457 - if (f.exists()) { 4.458 - result.add(new Archive(f, ClassFileReader.newInstance(f))); 4.459 + List<Path> files = new ArrayList<>(); 4.460 + // wildcard to parse all JAR files e.g. -classpath dir/* 4.461 + int i = p.lastIndexOf(".*"); 4.462 + if (i > 0) { 4.463 + Path dir = Paths.get(p.substring(0, i)); 4.464 + try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) { 4.465 + for (Path entry : stream) { 4.466 + files.add(entry); 4.467 + } 4.468 + } 4.469 + } else { 4.470 + files.add(Paths.get(p)); 4.471 + } 4.472 + for (Path f : files) { 4.473 + if (Files.exists(f)) { 4.474 + result.add(new Archive(f, ClassFileReader.newInstance(f))); 4.475 + } 4.476 } 4.477 } 4.478 } 4.479 return result; 4.480 } 4.481 + 4.482 + 4.483 + /** 4.484 + * Returns the file name of the archive for non-JRE class or 4.485 + * internal JRE classes. It returns empty string for SE API. 4.486 + */ 4.487 + private static String getArchiveName(Archive source, String profile) { 4.488 + String name = source.getFileName(); 4.489 + if (source instanceof JDKArchive) 4.490 + return profile.isEmpty() ? "JDK internal API (" + name + ")" : ""; 4.491 + return name; 4.492 + } 4.493 + 4.494 + class RawOutputFormatter implements Analyzer.Visitor { 4.495 + private final PrintWriter writer; 4.496 + RawOutputFormatter(PrintWriter writer) { 4.497 + this.writer = writer; 4.498 + } 4.499 + 4.500 + private String pkg = ""; 4.501 + @Override 4.502 + public void visitDependence(String origin, Archive source, 4.503 + String target, Archive archive, String profile) { 4.504 + if (!origin.equals(pkg)) { 4.505 + pkg = origin; 4.506 + writer.format(" %s (%s)%n", origin, source.getFileName()); 4.507 + } 4.508 + String name = (options.showProfile && !profile.isEmpty()) 4.509 + ? profile 4.510 + : getArchiveName(archive, profile); 4.511 + writer.format(" -> %-50s %s%n", target, name); 4.512 + } 4.513 + 4.514 + @Override 4.515 + public void visitArchiveDependence(Archive origin, Archive target, String profile) { 4.516 + writer.format("%s -> %s", origin, target); 4.517 + if (options.showProfile && !profile.isEmpty()) { 4.518 + writer.format(" (%s)%n", profile); 4.519 + } else { 4.520 + writer.format("%n"); 4.521 + } 4.522 + } 4.523 + } 4.524 + 4.525 + class DotFileFormatter implements Analyzer.Visitor, AutoCloseable { 4.526 + private final PrintWriter writer; 4.527 + private final String name; 4.528 + DotFileFormatter(PrintWriter writer, String name) { 4.529 + this.writer = writer; 4.530 + this.name = name; 4.531 + writer.format("digraph \"%s\" {%n", name); 4.532 + } 4.533 + DotFileFormatter(PrintWriter writer, Archive archive) { 4.534 + this.writer = writer; 4.535 + this.name = archive.getFileName(); 4.536 + writer.format("digraph \"%s\" {%n", name); 4.537 + writer.format(" // Path: %s%n", archive.toString()); 4.538 + } 4.539 + 4.540 + @Override 4.541 + public void close() { 4.542 + writer.println("}"); 4.543 + } 4.544 + 4.545 + private final Set<String> edges = new HashSet<>(); 4.546 + private String node = ""; 4.547 + @Override 4.548 + public void visitDependence(String origin, Archive source, 4.549 + String target, Archive archive, String profile) { 4.550 + if (!node.equals(origin)) { 4.551 + edges.clear(); 4.552 + node = origin; 4.553 + } 4.554 + // if -P option is specified, package name -> profile will 4.555 + // be shown and filter out multiple same edges. 4.556 + if (!edges.contains(target)) { 4.557 + StringBuilder sb = new StringBuilder(); 4.558 + String name = options.showProfile && !profile.isEmpty() 4.559 + ? profile 4.560 + : getArchiveName(archive, profile); 4.561 + writer.format(" %-50s -> %s;%n", 4.562 + String.format("\"%s\"", origin), 4.563 + name.isEmpty() ? String.format("\"%s\"", target) 4.564 + : String.format("\"%s (%s)\"", target, name)); 4.565 + edges.add(target); 4.566 + } 4.567 + } 4.568 + 4.569 + @Override 4.570 + public void visitArchiveDependence(Archive origin, Archive target, String profile) { 4.571 + String name = options.showProfile && !profile.isEmpty() 4.572 + ? profile : ""; 4.573 + writer.format(" %-30s -> \"%s\";%n", 4.574 + String.format("\"%s\"", origin.getFileName()), 4.575 + name.isEmpty() 4.576 + ? target.getFileName() 4.577 + : String.format("%s (%s)", target.getFileName(), name)); 4.578 + } 4.579 + } 4.580 }
5.1 --- a/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java Thu Oct 17 13:50:00 2013 +0200 5.2 +++ b/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java Thu Oct 17 13:19:48 2013 -0700 5.3 @@ -24,11 +24,11 @@ 5.4 */ 5.5 package com.sun.tools.jdeps; 5.6 5.7 -import java.io.File; 5.8 import java.io.IOException; 5.9 import java.nio.file.FileVisitResult; 5.10 import java.nio.file.Files; 5.11 import java.nio.file.Path; 5.12 +import java.nio.file.Paths; 5.13 import java.nio.file.SimpleFileVisitor; 5.14 import java.nio.file.attribute.BasicFileAttributes; 5.15 import java.util.*; 5.16 @@ -38,45 +38,38 @@ 5.17 */ 5.18 class PlatformClassPath { 5.19 private final static List<Archive> javaHomeArchives = init(); 5.20 + 5.21 static List<Archive> getArchives() { 5.22 return javaHomeArchives; 5.23 } 5.24 5.25 - static boolean contains(Archive archive) { 5.26 - return javaHomeArchives.contains(archive); 5.27 + private static List<Archive> init() { 5.28 + List<Archive> result = new ArrayList<>(); 5.29 + Path home = Paths.get(System.getProperty("java.home")); 5.30 + try { 5.31 + if (home.endsWith("jre")) { 5.32 + // jar files in <javahome>/jre/lib 5.33 + result.addAll(addJarFiles(home.resolve("lib"))); 5.34 + } else if (Files.exists(home.resolve("lib"))) { 5.35 + // either a JRE or a jdk build image 5.36 + Path classes = home.resolve("classes"); 5.37 + if (Files.isDirectory(classes)) { 5.38 + // jdk build outputdir 5.39 + result.add(new JDKArchive(classes, ClassFileReader.newInstance(classes))); 5.40 + } 5.41 + // add other JAR files 5.42 + result.addAll(addJarFiles(home.resolve("lib"))); 5.43 + } else { 5.44 + throw new RuntimeException("\"" + home + "\" not a JDK home"); 5.45 + } 5.46 + return result; 5.47 + } catch (IOException e) { 5.48 + throw new Error(e); 5.49 + } 5.50 } 5.51 5.52 - private static List<Archive> init() { 5.53 - List<Archive> result = new ArrayList<Archive>(); 5.54 - String javaHome = System.getProperty("java.home"); 5.55 - File jre = new File(javaHome, "jre"); 5.56 - File lib = new File(javaHome, "lib"); 5.57 - 5.58 - try { 5.59 - if (jre.exists() && jre.isDirectory()) { 5.60 - result.addAll(addJarFiles(new File(jre, "lib"))); 5.61 - result.addAll(addJarFiles(lib)); 5.62 - } else if (lib.exists() && lib.isDirectory()) { 5.63 - // either a JRE or a jdk build image 5.64 - File classes = new File(javaHome, "classes"); 5.65 - if (classes.exists() && classes.isDirectory()) { 5.66 - // jdk build outputdir 5.67 - result.add(new Archive(classes, ClassFileReader.newInstance(classes))); 5.68 - } 5.69 - // add other JAR files 5.70 - result.addAll(addJarFiles(lib)); 5.71 - } else { 5.72 - throw new RuntimeException("\"" + javaHome + "\" not a JDK home"); 5.73 - } 5.74 - } catch (IOException e) { 5.75 - throw new RuntimeException(e); 5.76 - } 5.77 - return result; 5.78 - } 5.79 - 5.80 - private static List<Archive> addJarFiles(File f) throws IOException { 5.81 - final List<Archive> result = new ArrayList<Archive>(); 5.82 - final Path root = f.toPath(); 5.83 + private static List<Archive> addJarFiles(final Path root) throws IOException { 5.84 + final List<Archive> result = new ArrayList<>(); 5.85 final Path ext = root.resolve("ext"); 5.86 Files.walkFileTree(root, new SimpleFileVisitor<Path>() { 5.87 @Override 5.88 @@ -91,17 +84,30 @@ 5.89 } 5.90 } 5.91 @Override 5.92 - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 5.93 + public FileVisitResult visitFile(Path p, BasicFileAttributes attrs) 5.94 throws IOException 5.95 { 5.96 - File f = file.toFile(); 5.97 - String fn = f.getName(); 5.98 - if (fn.endsWith(".jar") && !fn.equals("alt-rt.jar")) { 5.99 - result.add(new Archive(f, ClassFileReader.newInstance(f))); 5.100 + String fn = p.getFileName().toString(); 5.101 + if (fn.endsWith(".jar")) { 5.102 + // JDK may cobundle with JavaFX that doesn't belong to any profile 5.103 + // Treat jfxrt.jar as regular Archive 5.104 + result.add(fn.equals("jfxrt.jar") 5.105 + ? new Archive(p, ClassFileReader.newInstance(p)) 5.106 + : new JDKArchive(p, ClassFileReader.newInstance(p))); 5.107 } 5.108 return FileVisitResult.CONTINUE; 5.109 } 5.110 }); 5.111 return result; 5.112 } 5.113 + 5.114 + /** 5.115 + * A JDK archive is part of the JDK containing the Java SE API 5.116 + * or implementation classes (i.e. JDK internal API) 5.117 + */ 5.118 + static class JDKArchive extends Archive { 5.119 + JDKArchive(Path p, ClassFileReader reader) { 5.120 + super(p, reader); 5.121 + } 5.122 + } 5.123 }
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/share/classes/com/sun/tools/jdeps/Profile.java Thu Oct 17 13:19:48 2013 -0700 6.3 @@ -0,0 +1,227 @@ 6.4 +/* 6.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. Oracle designates this 6.11 + * particular file as subject to the "Classpath" exception as provided 6.12 + * by Oracle in the LICENSE file that accompanied this code. 6.13 + * 6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.17 + * version 2 for more details (a copy is included in the LICENSE file that 6.18 + * accompanied this code). 6.19 + * 6.20 + * You should have received a copy of the GNU General Public License version 6.21 + * 2 along with this work; if not, write to the Free Software Foundation, 6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.23 + * 6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.25 + * or visit www.oracle.com if you need additional information or have any 6.26 + * questions. 6.27 + */ 6.28 +package com.sun.tools.jdeps; 6.29 + 6.30 +import com.sun.tools.classfile.Annotation; 6.31 +import com.sun.tools.classfile.Annotation.*; 6.32 +import com.sun.tools.classfile.Attribute; 6.33 +import com.sun.tools.classfile.ClassFile; 6.34 +import com.sun.tools.classfile.ConstantPool.*; 6.35 +import com.sun.tools.classfile.ConstantPoolException; 6.36 +import com.sun.tools.classfile.RuntimeAnnotations_attribute; 6.37 +import java.io.FileReader; 6.38 +import java.io.IOException; 6.39 +import java.nio.file.Files; 6.40 +import java.nio.file.Path; 6.41 +import java.nio.file.Paths; 6.42 +import java.util.*; 6.43 +import java.util.jar.JarFile; 6.44 + 6.45 +/** 6.46 + * Build the profile information from ct.sym if exists. 6.47 + */ 6.48 +enum Profile { 6.49 + 6.50 + COMPACT1("compact1", 1), 6.51 + COMPACT2("compact2", 2), 6.52 + COMPACT3("compact3", 3), 6.53 + FULL_JRE("Full JRE", 4); 6.54 + 6.55 + final String name; 6.56 + final int profile; 6.57 + final Set<String> packages; 6.58 + final Set<String> proprietaryPkgs; 6.59 + 6.60 + Profile(String name, int profile) { 6.61 + this.name = name; 6.62 + this.profile = profile; 6.63 + this.packages = new HashSet<>(); 6.64 + this.proprietaryPkgs = new HashSet<>(); 6.65 + } 6.66 + 6.67 + @Override 6.68 + public String toString() { 6.69 + return name; 6.70 + } 6.71 + 6.72 + public static int getProfileCount() { 6.73 + return PackageToProfile.map.values().size(); 6.74 + } 6.75 + 6.76 + /** 6.77 + * Returns the Profile for the given package name. It returns an empty 6.78 + * string if the given package is not in any profile. 6.79 + */ 6.80 + public static Profile getProfile(String pn) { 6.81 + Profile profile = PackageToProfile.map.get(pn); 6.82 + return (profile != null && profile.packages.contains(pn)) 6.83 + ? profile : null; 6.84 + } 6.85 + 6.86 + static class PackageToProfile { 6.87 + static Map<String, Profile> map = initProfiles(); 6.88 + 6.89 + private static Map<String, Profile> initProfiles() { 6.90 + try { 6.91 + String profilesProps = System.getProperty("jdeps.profiles"); 6.92 + if (profilesProps != null) { 6.93 + // for testing for JDK development build where ct.sym doesn't exist 6.94 + initProfilesFromProperties(profilesProps); 6.95 + } else { 6.96 + Path home = Paths.get(System.getProperty("java.home")); 6.97 + if (home.endsWith("jre")) { 6.98 + home = home.getParent(); 6.99 + } 6.100 + Path ctsym = home.resolve("lib").resolve("ct.sym"); 6.101 + if (Files.exists(ctsym)) { 6.102 + // parse ct.sym and load information about profiles 6.103 + try (JarFile jf = new JarFile(ctsym.toFile())) { 6.104 + ClassFileReader reader = ClassFileReader.newInstance(ctsym, jf); 6.105 + for (ClassFile cf : reader.getClassFiles()) { 6.106 + findProfile(cf); 6.107 + } 6.108 + } 6.109 + } 6.110 + } 6.111 + } catch (IOException | ConstantPoolException e) { 6.112 + throw new Error(e); 6.113 + } 6.114 + HashMap<String,Profile> map = new HashMap<>(); 6.115 + for (Profile profile : Profile.values()) { 6.116 + for (String pn : profile.packages) { 6.117 + if (!map.containsKey(pn)) { 6.118 + // split packages in the JRE: use the smaller compact 6.119 + map.put(pn, profile); 6.120 + } 6.121 + } 6.122 + for (String pn : profile.proprietaryPkgs) { 6.123 + if (!map.containsKey(pn)) { 6.124 + map.put(pn, profile); 6.125 + } 6.126 + } 6.127 + } 6.128 + return map; 6.129 + } 6.130 + private static final String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;"; 6.131 + private static final String PROPRIETARY_ANNOTATION = "Lsun/Proprietary+Annotation;"; 6.132 + private static Profile findProfile(ClassFile cf) throws ConstantPoolException { 6.133 + RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) 6.134 + cf.attributes.get(Attribute.RuntimeInvisibleAnnotations); 6.135 + int index = 0; 6.136 + boolean proprietary = false; 6.137 + if (attr != null) { 6.138 + for (int i = 0; i < attr.annotations.length; i++) { 6.139 + Annotation ann = attr.annotations[i]; 6.140 + String annType = cf.constant_pool.getUTF8Value(ann.type_index); 6.141 + if (PROFILE_ANNOTATION.equals(annType)) { 6.142 + for (int j = 0; j < ann.num_element_value_pairs; j++) { 6.143 + Annotation.element_value_pair pair = ann.element_value_pairs[j]; 6.144 + Primitive_element_value ev = (Primitive_element_value) pair.value; 6.145 + CONSTANT_Integer_info info = (CONSTANT_Integer_info) 6.146 + cf.constant_pool.get(ev.const_value_index); 6.147 + index = info.value; 6.148 + break; 6.149 + } 6.150 + } else if (PROPRIETARY_ANNOTATION.equals(annType)) { 6.151 + proprietary = true; 6.152 + } 6.153 + } 6.154 + } 6.155 + 6.156 + Profile p = null; // default 6.157 + switch (index) { 6.158 + case 1: 6.159 + p = Profile.COMPACT1; break; 6.160 + case 2: 6.161 + p = Profile.COMPACT2; break; 6.162 + case 3: 6.163 + p = Profile.COMPACT3; break; 6.164 + case 4: 6.165 + p = Profile.FULL_JRE; break; 6.166 + default: 6.167 + // skip classes with profile=0 6.168 + // Inner classes are not annotated with the profile annotation 6.169 + return null; 6.170 + } 6.171 + 6.172 + String name = cf.getName(); 6.173 + int i = name.lastIndexOf('/'); 6.174 + name = (i > 0) ? name.substring(0, i).replace('/', '.') : ""; 6.175 + if (proprietary) { 6.176 + p.proprietaryPkgs.add(name); 6.177 + } else { 6.178 + p.packages.add(name); 6.179 + } 6.180 + return p; 6.181 + } 6.182 + 6.183 + private static void initProfilesFromProperties(String path) throws IOException { 6.184 + Properties props = new Properties(); 6.185 + try (FileReader reader = new FileReader(path)) { 6.186 + props.load(reader); 6.187 + } 6.188 + for (Profile prof : Profile.values()) { 6.189 + int i = prof.profile; 6.190 + String key = props.getProperty("profile." + i + ".name"); 6.191 + if (key == null) { 6.192 + throw new RuntimeException(key + " missing in " + path); 6.193 + } 6.194 + String n = props.getProperty("profile." + i + ".packages"); 6.195 + String[] pkgs = n.split("\\s+"); 6.196 + for (String p : pkgs) { 6.197 + if (p.isEmpty()) continue; 6.198 + prof.packages.add(p); 6.199 + } 6.200 + } 6.201 + } 6.202 + } 6.203 + 6.204 + // for debugging 6.205 + public static void main(String[] args) { 6.206 + if (args.length == 0) { 6.207 + if (Profile.getProfileCount() == 0) { 6.208 + System.err.println("No profile is present in this JDK"); 6.209 + } 6.210 + for (Profile p : Profile.values()) { 6.211 + String profileName = p.name; 6.212 + SortedSet<String> set = new TreeSet<>(p.packages); 6.213 + for (String s : set) { 6.214 + // filter out the inner classes that are not annotated with 6.215 + // the profile annotation 6.216 + if (PackageToProfile.map.get(s) == p) { 6.217 + System.out.format("%2d: %-10s %s%n", p.profile, profileName, s); 6.218 + profileName = ""; 6.219 + } else { 6.220 + System.err.format("Split package: %s in %s and %s %n", 6.221 + s, PackageToProfile.map.get(s).name, p.name); 6.222 + } 6.223 + } 6.224 + } 6.225 + } 6.226 + for (String pn : args) { 6.227 + System.out.format("%s in %s%n", pn, getProfile(pn)); 6.228 + } 6.229 + } 6.230 +}
7.1 --- a/src/share/classes/com/sun/tools/jdeps/Profiles.java Thu Oct 17 13:50:00 2013 +0200 7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 7.3 @@ -1,241 +0,0 @@ 7.4 -/* 7.5 - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 7.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 - * 7.8 - * This code is free software; you can redistribute it and/or modify it 7.9 - * under the terms of the GNU General Public License version 2 only, as 7.10 - * published by the Free Software Foundation. Oracle designates this 7.11 - * particular file as subject to the "Classpath" exception as provided 7.12 - * by Oracle in the LICENSE file that accompanied this code. 7.13 - * 7.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 7.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.17 - * version 2 for more details (a copy is included in the LICENSE file that 7.18 - * accompanied this code). 7.19 - * 7.20 - * You should have received a copy of the GNU General Public License version 7.21 - * 2 along with this work; if not, write to the Free Software Foundation, 7.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.23 - * 7.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.25 - * or visit www.oracle.com if you need additional information or have any 7.26 - * questions. 7.27 - */ 7.28 -package com.sun.tools.jdeps; 7.29 - 7.30 -import com.sun.tools.classfile.Annotation; 7.31 -import com.sun.tools.classfile.Annotation.*; 7.32 -import com.sun.tools.classfile.Attribute; 7.33 -import com.sun.tools.classfile.ClassFile; 7.34 -import com.sun.tools.classfile.ConstantPool; 7.35 -import com.sun.tools.classfile.ConstantPool.*; 7.36 -import com.sun.tools.classfile.ConstantPoolException; 7.37 -import com.sun.tools.classfile.RuntimeAnnotations_attribute; 7.38 -import java.io.File; 7.39 -import java.io.FileReader; 7.40 -import java.io.IOException; 7.41 -import java.nio.file.Path; 7.42 -import java.nio.file.Paths; 7.43 -import java.util.*; 7.44 -import java.util.jar.JarFile; 7.45 - 7.46 -/** 7.47 - * Build the profile information from ct.sym if exists. 7.48 - */ 7.49 -class Profiles { 7.50 - private static final Map<String,Profile> map = initProfiles(); 7.51 - /** 7.52 - * Returns the name of the profile for the given package name. 7.53 - * It returns an empty string if the given package is not in any profile. 7.54 - */ 7.55 - public static String getProfileName(String pn) { 7.56 - Profile profile = map.get(pn); 7.57 - return (profile != null && profile.packages.contains(pn)) 7.58 - ? profile.name : ""; 7.59 - } 7.60 - 7.61 - public static int getProfileCount() { 7.62 - return new HashSet<Profile>(map.values()).size(); 7.63 - } 7.64 - 7.65 - private static Map<String,Profile> initProfiles() { 7.66 - List<Profile> profiles = new ArrayList<Profile>(); 7.67 - try { 7.68 - String profilesProps = System.getProperty("jdeps.profiles"); 7.69 - if (profilesProps != null) { 7.70 - // for testing for JDK development build where ct.sym doesn't exist 7.71 - initProfilesFromProperties(profiles, profilesProps); 7.72 - } else { 7.73 - Path home = Paths.get(System.getProperty("java.home")); 7.74 - if (home.endsWith("jre")) { 7.75 - home = home.getParent(); 7.76 - } 7.77 - Path ctsym = home.resolve("lib").resolve("ct.sym"); 7.78 - if (ctsym.toFile().exists()) { 7.79 - // add a default Full JRE 7.80 - profiles.add(0, new Profile("Full JRE", 0)); 7.81 - // parse ct.sym and load information about profiles 7.82 - try (JarFile jf = new JarFile(ctsym.toFile())) { 7.83 - ClassFileReader reader = ClassFileReader.newInstance(ctsym, jf); 7.84 - for (ClassFile cf : reader.getClassFiles()) { 7.85 - findProfile(profiles, cf); 7.86 - } 7.87 - } 7.88 - 7.89 - // merge the last Profile with the "Full JRE" 7.90 - if (profiles.size() > 1) { 7.91 - Profile fullJRE = profiles.get(0); 7.92 - Profile p = profiles.remove(profiles.size() - 1); 7.93 - for (String pn : fullJRE.packages) { 7.94 - // The last profile contains the packages determined from ct.sym. 7.95 - // Move classes annotated profile==0 or no attribute that are 7.96 - // added in the fullJRE profile to either supported or proprietary 7.97 - // packages appropriately 7.98 - if (p.proprietaryPkgs.contains(pn)) { 7.99 - p.proprietaryPkgs.add(pn); 7.100 - } else { 7.101 - p.packages.add(pn); 7.102 - } 7.103 - } 7.104 - fullJRE.packages.clear(); 7.105 - fullJRE.proprietaryPkgs.clear(); 7.106 - fullJRE.packages.addAll(p.packages); 7.107 - fullJRE.proprietaryPkgs.addAll(p.proprietaryPkgs); 7.108 - } 7.109 - } 7.110 - } 7.111 - } catch (IOException | ConstantPoolException e) { 7.112 - throw new Error(e); 7.113 - } 7.114 - HashMap<String,Profile> map = new HashMap<String,Profile>(); 7.115 - for (Profile profile : profiles) { 7.116 - // Inner classes are not annotated with the profile annotation 7.117 - // packages may be in one profile but also appear in the Full JRE 7.118 - // Full JRE is always the first element in profiles list and 7.119 - // so the map will contain the appropriate Profile 7.120 - for (String pn : profile.packages) { 7.121 - map.put(pn, profile); 7.122 - } 7.123 - for (String pn : profile.proprietaryPkgs) { 7.124 - map.put(pn, profile); 7.125 - } 7.126 - } 7.127 - return map; 7.128 - } 7.129 - 7.130 - private static final String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;"; 7.131 - private static final String PROPRIETARY_ANNOTATION = "Lsun/Proprietary+Annotation;"; 7.132 - private static Profile findProfile(List<Profile> profiles, ClassFile cf) 7.133 - throws ConstantPoolException 7.134 - { 7.135 - RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) 7.136 - cf.attributes.get(Attribute.RuntimeInvisibleAnnotations); 7.137 - int index = 0; 7.138 - boolean proprietary = false; 7.139 - if (attr != null) { 7.140 - for (int i = 0; i < attr.annotations.length; i++) { 7.141 - Annotation ann = attr.annotations[i]; 7.142 - String annType = cf.constant_pool.getUTF8Value(ann.type_index); 7.143 - if (PROFILE_ANNOTATION.equals(annType)) { 7.144 - for (int j = 0; j < ann.num_element_value_pairs; j++) { 7.145 - Annotation.element_value_pair pair = ann.element_value_pairs[j]; 7.146 - Primitive_element_value ev = (Primitive_element_value)pair.value; 7.147 - CONSTANT_Integer_info info = (CONSTANT_Integer_info) 7.148 - cf.constant_pool.get(ev.const_value_index); 7.149 - index = info.value; 7.150 - break; 7.151 - } 7.152 - } else if (PROPRIETARY_ANNOTATION.equals(annType)) { 7.153 - proprietary = true; 7.154 - } 7.155 - } 7.156 - if (index >= profiles.size()) { 7.157 - Profile p = null; 7.158 - for (int i = profiles.size(); i <= index; i++) { 7.159 - p = new Profile(i); 7.160 - profiles.add(p); 7.161 - } 7.162 - } 7.163 - } 7.164 - 7.165 - Profile p = profiles.get(index); 7.166 - String name = cf.getName(); 7.167 - int i = name.lastIndexOf('/'); 7.168 - name = (i > 0) ? name.substring(0, i).replace('/','.') : ""; 7.169 - if (proprietary) { 7.170 - p.proprietaryPkgs.add(name); 7.171 - } else { 7.172 - p.packages.add(name); 7.173 - } 7.174 - return p; 7.175 - } 7.176 - 7.177 - private static void initProfilesFromProperties(List<Profile> profiles, String path) 7.178 - throws IOException 7.179 - { 7.180 - Properties props = new Properties(); 7.181 - try (FileReader reader = new FileReader(path)) { 7.182 - props.load(reader); 7.183 - } 7.184 - int i=1; 7.185 - String key; 7.186 - while (props.containsKey((key = "profile." + i + ".name"))) { 7.187 - Profile profile = new Profile(props.getProperty(key), i); 7.188 - profiles.add(profile); 7.189 - String n = props.getProperty("profile." + i + ".packages"); 7.190 - String[] pkgs = n.split("\\s+"); 7.191 - for (String p : pkgs) { 7.192 - if (p.isEmpty()) continue; 7.193 - profile.packages.add(p); 7.194 - } 7.195 - i++; 7.196 - } 7.197 - } 7.198 - 7.199 - private static class Profile { 7.200 - final String name; 7.201 - final int profile; 7.202 - final Set<String> packages; 7.203 - final Set<String> proprietaryPkgs; 7.204 - Profile(int profile) { 7.205 - this("compact" + profile, profile); 7.206 - } 7.207 - Profile(String name, int profile) { 7.208 - this.name = name; 7.209 - this.profile = profile; 7.210 - this.packages = new HashSet<String>(); 7.211 - this.proprietaryPkgs = new HashSet<String>(); 7.212 - } 7.213 - public String toString() { 7.214 - return name; 7.215 - } 7.216 - } 7.217 - 7.218 - // for debugging 7.219 - public static void main(String[] args) { 7.220 - if (args.length == 0) { 7.221 - Profile[] profiles = new Profile[getProfileCount()]; 7.222 - for (Profile p : map.values()) { 7.223 - // move the zeroth profile to the last 7.224 - int index = p.profile == 0 ? profiles.length-1 : p.profile-1; 7.225 - profiles[index] = p; 7.226 - } 7.227 - for (Profile p : profiles) { 7.228 - String profileName = p.name; 7.229 - SortedSet<String> set = new TreeSet<String>(p.packages); 7.230 - for (String s : set) { 7.231 - // filter out the inner classes that are not annotated with 7.232 - // the profile annotation 7.233 - if (map.get(s) == p) { 7.234 - System.out.format("%-10s %s%n", profileName, s); 7.235 - profileName = ""; 7.236 - } 7.237 - } 7.238 - } 7.239 - } 7.240 - for (String pn : args) { 7.241 - System.out.format("%s in %s%n", pn, getProfileName(pn)); 7.242 - } 7.243 - } 7.244 -}
8.1 --- a/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Thu Oct 17 13:50:00 2013 +0200 8.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Thu Oct 17 13:19:48 2013 -0700 8.3 @@ -5,46 +5,63 @@ 8.4 main.usage=\ 8.5 Usage: {0} <options> <classes...>\n\ 8.6 where <classes> can be a pathname to a .class file, a directory, a JAR file,\n\ 8.7 -or a fully-qualified classname or wildcard "*". Possible options include: 8.8 +or a fully-qualified class name. Possible options include: 8.9 8.10 error.prefix=Error: 8.11 warn.prefix=Warning: 8.12 8.13 main.opt.h=\ 8.14 -\ -h -? --help Print this usage message 8.15 +\ -h -? -help Print this usage message 8.16 8.17 main.opt.version=\ 8.18 -\ --version Version information 8.19 - 8.20 -main.opt.V=\ 8.21 -\ -V <level> --verbose-level=<level> Print package-level or class-level dependencies\n\ 8.22 -\ Valid levels are: "package" and "class" 8.23 +\ -version Version information 8.24 8.25 main.opt.v=\ 8.26 -\ -v --verbose Print additional information 8.27 +\ -v -verbose Print all class level dependencies\n\ 8.28 +\ -verbose:package Print package-level dependencies excluding\n\ 8.29 +\ dependencies within the same archive\n\ 8.30 +\ -verbose:class Print class-level dependencies excluding\n\ 8.31 +\ dependencies within the same archive 8.32 8.33 main.opt.s=\ 8.34 -\ -s --summary Print dependency summary only 8.35 +\ -s -summary Print dependency summary only 8.36 8.37 main.opt.p=\ 8.38 -\ -p <pkg name> --package=<pkg name> Restrict analysis to classes in this package\n\ 8.39 -\ (may be given multiple times) 8.40 +\ -p <pkgname> -package <pkgname> Finds dependences in the given package\n\ 8.41 +\ (may be given multiple times) 8.42 8.43 main.opt.e=\ 8.44 -\ -e <regex> --regex=<regex> Restrict analysis to packages matching pattern\n\ 8.45 -\ (-p and -e are exclusive) 8.46 +\ -e <regex> -regex <regex> Finds dependences in packages matching pattern\n\ 8.47 +\ (-p and -e are exclusive) 8.48 + 8.49 +main.opt.include=\ 8.50 +\ -include <regex> Restrict analysis to classes matching pattern\n\ 8.51 +\ This option filters the list of classes to\n\ 8.52 +\ be analyzed. It can be used together with\n\ 8.53 +\ -p and -e which apply pattern to the dependences 8.54 8.55 main.opt.P=\ 8.56 -\ -P --profile Show profile or the file containing a package 8.57 +\ -P -profile Show profile or the file containing a package 8.58 8.59 -main.opt.c=\ 8.60 -\ -c <path> --classpath=<path> Specify where to find class files 8.61 +main.opt.cp=\ 8.62 +\ -cp <path> -classpath <path> Specify where to find class files 8.63 8.64 main.opt.R=\ 8.65 -\ -R --recursive Recursively traverse all dependencies 8.66 +\ -R -recursive Recursively traverse all dependencies 8.67 8.68 -main.opt.d=\ 8.69 -\ -d <depth> --depth=<depth> Specify the depth of the transitive dependency analysis 8.70 +main.opt.apionly=\ 8.71 +\ -apionly Restrict analysis to APIs i.e. dependences\n\ 8.72 +\ from the signature of public and protected\n\ 8.73 +\ members of public classes including field\n\ 8.74 +\ type, method parameter types, returned type,\n\ 8.75 +\ checked exception types etc 8.76 + 8.77 +main.opt.dotoutput=\ 8.78 +\ -dotoutput <dir> Destination directory for DOT file output 8.79 + 8.80 +main.opt.depth=\ 8.81 +\ -depth=<depth> Specify the depth of the transitive\n\ 8.82 +\ dependency analysis 8.83 8.84 err.unknown.option=unknown option: {0} 8.85 err.missing.arg=no value given for {0} 8.86 @@ -53,6 +70,7 @@ 8.87 err.option.after.class=option must be specified before classes: {0} 8.88 err.option.unsupported={0} not supported: {1} 8.89 err.profiles.msg=No profile information 8.90 +err.dot.output.path=invalid path: {0} 8.91 warn.invalid.arg=Invalid classname or pathname not exist: {0} 8.92 warn.split.package=package {0} defined in {1} {2} 8.93
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/test/tools/jdeps/APIDeps.java Thu Oct 17 13:19:48 2013 -0700 9.3 @@ -0,0 +1,191 @@ 9.4 +/* 9.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.7 + * 9.8 + * This code is free software; you can redistribute it and/or modify it 9.9 + * under the terms of the GNU General Public License version 2 only, as 9.10 + * published by the Free Software Foundation. 9.11 + * 9.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 9.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 9.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 9.15 + * version 2 for more details (a copy is included in the LICENSE file that 9.16 + * accompanied this code). 9.17 + * 9.18 + * You should have received a copy of the GNU General Public License version 9.19 + * 2 along with this work; if not, write to the Free Software Foundation, 9.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 9.21 + * 9.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 9.23 + * or visit www.oracle.com if you need additional information or have any 9.24 + * questions. 9.25 + */ 9.26 + 9.27 +/* 9.28 + * @test 9.29 + * @bug 8015912 9.30 + * @summary find API dependencies 9.31 + * @build m.Bar m.Foo m.Gee b.B c.C c.I d.D e.E f.F g.G 9.32 + * @run main APIDeps 9.33 + */ 9.34 + 9.35 +import java.io.File; 9.36 +import java.io.IOException; 9.37 +import java.io.PrintWriter; 9.38 +import java.io.StringWriter; 9.39 +import java.nio.file.Path; 9.40 +import java.nio.file.Paths; 9.41 +import java.util.*; 9.42 +import java.util.regex.*; 9.43 + 9.44 +public class APIDeps { 9.45 + private static boolean symbolFileExist = initProfiles(); 9.46 + private static boolean initProfiles() { 9.47 + // check if ct.sym exists; if not use the profiles.properties file 9.48 + Path home = Paths.get(System.getProperty("java.home")); 9.49 + if (home.endsWith("jre")) { 9.50 + home = home.getParent(); 9.51 + } 9.52 + Path ctsym = home.resolve("lib").resolve("ct.sym"); 9.53 + boolean symbolExists = ctsym.toFile().exists(); 9.54 + if (!symbolExists) { 9.55 + Path testSrcProfiles = 9.56 + Paths.get(System.getProperty("test.src", "."), "profiles.properties"); 9.57 + if (!testSrcProfiles.toFile().exists()) 9.58 + throw new Error(testSrcProfiles + " does not exist"); 9.59 + System.out.format("%s doesn't exist.%nUse %s to initialize profiles info%n", 9.60 + ctsym, testSrcProfiles); 9.61 + System.setProperty("jdeps.profiles", testSrcProfiles.toString()); 9.62 + } 9.63 + return symbolExists; 9.64 + } 9.65 + 9.66 + public static void main(String... args) throws Exception { 9.67 + int errors = 0; 9.68 + errors += new APIDeps().run(); 9.69 + if (errors > 0) 9.70 + throw new Exception(errors + " errors found"); 9.71 + } 9.72 + 9.73 + int run() throws IOException { 9.74 + File testDir = new File(System.getProperty("test.classes", ".")); 9.75 + String testDirBasename = testDir.toPath().getFileName().toString(); 9.76 + File mDir = new File(testDir, "m"); 9.77 + // all dependencies 9.78 + test(new File(mDir, "Bar.class"), 9.79 + new String[] {"java.lang.Object", "java.lang.String", 9.80 + "java.util.Set", "java.util.HashSet", 9.81 + "java.lang.management.ManagementFactory", 9.82 + "java.lang.management.RuntimeMXBean", 9.83 + "b.B", "c.C", "d.D", "f.F", "g.G"}, 9.84 + new String[] {"compact1", "compact3", testDirBasename}, 9.85 + new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"}); 9.86 + test(new File(mDir, "Foo.class"), 9.87 + new String[] {"c.I", "e.E", "f.F", "m.Bar"}, 9.88 + new String[] {testDirBasename}, 9.89 + new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"}); 9.90 + test(new File(mDir, "Gee.class"), 9.91 + new String[] {"g.G", "sun.misc.Lock"}, 9.92 + new String[] {testDirBasename, "JDK internal API"}, 9.93 + new String[] {"-classpath", testDir.getPath(), "-verbose"}); 9.94 + // parse only APIs 9.95 + test(mDir, 9.96 + new String[] {"java.lang.Object", "java.lang.String", 9.97 + "java.util.Set", 9.98 + "c.C", "d.D", "c.I", "e.E", "m.Bar"}, 9.99 + new String[] {"compact1", testDirBasename, mDir.getName()}, 9.100 + new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "-apionly"}); 9.101 + return errors; 9.102 + } 9.103 + 9.104 + void test(File file, String[] expect, String[] profiles) { 9.105 + test(file, expect, profiles, new String[0]); 9.106 + } 9.107 + 9.108 + void test(File file, String[] expect, String[] profiles, String[] options) { 9.109 + List<String> args = new ArrayList<>(Arrays.asList(options)); 9.110 + if (file != null) { 9.111 + args.add(file.getPath()); 9.112 + } 9.113 + checkResult("api-dependencies", expect, profiles, 9.114 + jdeps(args.toArray(new String[0]))); 9.115 + } 9.116 + 9.117 + Map<String,String> jdeps(String... args) { 9.118 + StringWriter sw = new StringWriter(); 9.119 + PrintWriter pw = new PrintWriter(sw); 9.120 + System.err.println("jdeps " + Arrays.toString(args)); 9.121 + int rc = com.sun.tools.jdeps.Main.run(args, pw); 9.122 + pw.close(); 9.123 + String out = sw.toString(); 9.124 + if (!out.isEmpty()) 9.125 + System.err.println(out); 9.126 + if (rc != 0) 9.127 + throw new Error("jdeps failed: rc=" + rc); 9.128 + return findDeps(out); 9.129 + } 9.130 + 9.131 + // Pattern used to parse lines 9.132 + private static Pattern linePattern = Pattern.compile(".*\r?\n"); 9.133 + private static Pattern pattern = Pattern.compile("\\s+ -> (\\S+) +(.*)"); 9.134 + 9.135 + // Use the linePattern to break the given String into lines, applying 9.136 + // the pattern to each line to see if we have a match 9.137 + private static Map<String,String> findDeps(String out) { 9.138 + Map<String,String> result = new HashMap<>(); 9.139 + Matcher lm = linePattern.matcher(out); // Line matcher 9.140 + Matcher pm = null; // Pattern matcher 9.141 + int lines = 0; 9.142 + while (lm.find()) { 9.143 + lines++; 9.144 + CharSequence cs = lm.group(); // The current line 9.145 + if (pm == null) 9.146 + pm = pattern.matcher(cs); 9.147 + else 9.148 + pm.reset(cs); 9.149 + if (pm.find()) 9.150 + result.put(pm.group(1), pm.group(2).trim()); 9.151 + if (lm.end() == out.length()) 9.152 + break; 9.153 + } 9.154 + return result; 9.155 + } 9.156 + 9.157 + void checkResult(String label, String[] expect, Collection<String> found) { 9.158 + List<String> list = Arrays.asList(expect); 9.159 + if (!isEqual(list, found)) 9.160 + error("Unexpected " + label + " found: '" + found + "', expected: '" + list + "'"); 9.161 + } 9.162 + 9.163 + void checkResult(String label, String[] expect, String[] profiles, Map<String,String> result) { 9.164 + // check the dependencies 9.165 + checkResult(label, expect, result.keySet()); 9.166 + // check profile information 9.167 + Set<String> values = new TreeSet<>(); 9.168 + String internal = "JDK internal API"; 9.169 + for (String s: result.values()) { 9.170 + if (s.startsWith(internal)){ 9.171 + values.add(internal); 9.172 + } else { 9.173 + values.add(s); 9.174 + } 9.175 + } 9.176 + checkResult(label, profiles, values); 9.177 + } 9.178 + 9.179 + boolean isEqual(List<String> expected, Collection<String> found) { 9.180 + if (expected.size() != found.size()) 9.181 + return false; 9.182 + 9.183 + List<String> list = new ArrayList<>(found); 9.184 + list.removeAll(expected); 9.185 + return list.isEmpty(); 9.186 + } 9.187 + 9.188 + void error(String msg) { 9.189 + System.err.println("Error: " + msg); 9.190 + errors++; 9.191 + } 9.192 + 9.193 + int errors; 9.194 +}
10.1 --- a/test/tools/jdeps/Basic.java Thu Oct 17 13:50:00 2013 +0200 10.2 +++ b/test/tools/jdeps/Basic.java Thu Oct 17 13:19:48 2013 -0700 10.3 @@ -23,7 +23,7 @@ 10.4 10.5 /* 10.6 * @test 10.7 - * @bug 8003562 8005428 10.8 + * @bug 8003562 8005428 8015912 10.9 * @summary Basic tests for jdeps tool 10.10 * @build Test p.Foo 10.11 * @run main Basic 10.12 @@ -79,40 +79,33 @@ 10.13 new String[] {"compact1", "compact1", "compact3"}); 10.14 // test class-level dependency output 10.15 test(new File(testDir, "Test.class"), 10.16 - new String[] {"java.lang.Object", "p.Foo"}, 10.17 - new String[] {"compact1", "not found"}, 10.18 - new String[] {"-V", "class"}); 10.19 + new String[] {"java.lang.Object", "java.lang.String", "p.Foo"}, 10.20 + new String[] {"compact1", "compact1", "not found"}, 10.21 + new String[] {"-verbose:class"}); 10.22 // test -p option 10.23 test(new File(testDir, "Test.class"), 10.24 new String[] {"p.Foo"}, 10.25 new String[] {"not found"}, 10.26 - new String[] {"--verbose-level=class", "-p", "p"}); 10.27 + new String[] {"-verbose:class", "-p", "p"}); 10.28 // test -e option 10.29 test(new File(testDir, "Test.class"), 10.30 new String[] {"p.Foo"}, 10.31 new String[] {"not found"}, 10.32 - new String[] {"-V", "class", "-e", "p\\..*"}); 10.33 + new String[] {"-verbose:class", "-e", "p\\..*"}); 10.34 test(new File(testDir, "Test.class"), 10.35 new String[] {"java.lang"}, 10.36 new String[] {"compact1"}, 10.37 - new String[] {"-V", "package", "-e", "java\\.lang\\..*"}); 10.38 - // test -classpath and wildcard options 10.39 + new String[] {"-verbose:package", "-e", "java\\.lang\\..*"}); 10.40 + // test -classpath and -include options 10.41 test(null, 10.42 - new String[] {"com.sun.tools.jdeps", "java.lang", "java.util", 10.43 - "java.util.regex", "java.io", "java.nio.file", 10.44 + new String[] {"java.lang", "java.util", 10.45 "java.lang.management"}, 10.46 - new String[] {(symbolFileExist? "not found" : "JDK internal API (classes)"), 10.47 - "compact1", "compact1", "compact1", 10.48 - "compact1", "compact1", "compact3"}, 10.49 - new String[] {"--classpath", testDir.getPath(), "*"}); 10.50 - /* Temporary disable this test case. Test.class has a dependency 10.51 - * on java.lang.String on certain windows machine (8008479). 10.52 - // -v shows intra-dependency 10.53 - test(new File(testDir, "Test.class"), 10.54 - new String[] {"java.lang.Object", "p.Foo"}, 10.55 - new String[] {"compact1", testDir.getName()}, 10.56 - new String[] {"-v", "--classpath", testDir.getPath(), "Test.class"}); 10.57 - */ 10.58 + new String[] {"compact1", "compact1", "compact3"}, 10.59 + new String[] {"-classpath", testDir.getPath(), "-include", "p.+|Test.class"}); 10.60 + test(new File(testDir, "Test.class"), 10.61 + new String[] {"java.lang.Object", "java.lang.String", "p.Foo"}, 10.62 + new String[] {"compact1", "compact1", testDir.getName()}, 10.63 + new String[] {"-v", "-classpath", testDir.getPath(), "Test.class"}); 10.64 return errors; 10.65 } 10.66
11.1 --- a/test/tools/jdeps/Test.java Thu Oct 17 13:50:00 2013 +0200 11.2 +++ b/test/tools/jdeps/Test.java Thu Oct 17 13:19:48 2013 -0700 11.3 @@ -25,4 +25,7 @@ 11.4 public void test() { 11.5 p.Foo f = new p.Foo(); 11.6 } 11.7 + private String name() { 11.8 + return "this test"; 11.9 + } 11.10 }
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/tools/jdeps/b/B.java Thu Oct 17 13:19:48 2013 -0700 12.3 @@ -0,0 +1,32 @@ 12.4 +/* 12.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 + * 12.8 + * This code is free software; you can redistribute it and/or modify it 12.9 + * under the terms of the GNU General Public License version 2 only, as 12.10 + * published by the Free Software Foundation. 12.11 + * 12.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 12.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.15 + * version 2 for more details (a copy is included in the LICENSE file that 12.16 + * accompanied this code). 12.17 + * 12.18 + * You should have received a copy of the GNU General Public License version 12.19 + * 2 along with this work; if not, write to the Free Software Foundation, 12.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.21 + * 12.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 12.23 + * or visit www.oracle.com if you need additional information or have any 12.24 + * questions. 12.25 + */ 12.26 + 12.27 +package b; 12.28 + 12.29 +import java.lang.annotation.*; 12.30 +import static java.lang.annotation.ElementType.*; 12.31 + 12.32 +@Retention(RetentionPolicy.RUNTIME) 12.33 +@Target({TYPE, METHOD, FIELD}) 12.34 +public @interface B { 12.35 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/test/tools/jdeps/c/C.java Thu Oct 17 13:19:48 2013 -0700 13.3 @@ -0,0 +1,27 @@ 13.4 +/* 13.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.7 + * 13.8 + * This code is free software; you can redistribute it and/or modify it 13.9 + * under the terms of the GNU General Public License version 2 only, as 13.10 + * published by the Free Software Foundation. 13.11 + * 13.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 13.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13.15 + * version 2 for more details (a copy is included in the LICENSE file that 13.16 + * accompanied this code). 13.17 + * 13.18 + * You should have received a copy of the GNU General Public License version 13.19 + * 2 along with this work; if not, write to the Free Software Foundation, 13.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 13.21 + * 13.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 13.23 + * or visit www.oracle.com if you need additional information or have any 13.24 + * questions. 13.25 + */ 13.26 + 13.27 +package c; 13.28 + 13.29 +public class C { 13.30 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/test/tools/jdeps/c/I.java Thu Oct 17 13:19:48 2013 -0700 14.3 @@ -0,0 +1,28 @@ 14.4 +/* 14.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.23 + * or visit www.oracle.com if you need additional information or have any 14.24 + * questions. 14.25 + */ 14.26 + 14.27 +package c; 14.28 + 14.29 +public interface I { 14.30 + void run(); 14.31 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/test/tools/jdeps/d/D.java Thu Oct 17 13:19:48 2013 -0700 15.3 @@ -0,0 +1,27 @@ 15.4 +/* 15.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 15.7 + * 15.8 + * This code is free software; you can redistribute it and/or modify it 15.9 + * under the terms of the GNU General Public License version 2 only, as 15.10 + * published by the Free Software Foundation. 15.11 + * 15.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 15.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15.15 + * version 2 for more details (a copy is included in the LICENSE file that 15.16 + * accompanied this code). 15.17 + * 15.18 + * You should have received a copy of the GNU General Public License version 15.19 + * 2 along with this work; if not, write to the Free Software Foundation, 15.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 15.21 + * 15.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 15.23 + * or visit www.oracle.com if you need additional information or have any 15.24 + * questions. 15.25 + */ 15.26 + 15.27 +package d; 15.28 + 15.29 +public class D { 15.30 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/test/tools/jdeps/e/E.java Thu Oct 17 13:19:48 2013 -0700 16.3 @@ -0,0 +1,28 @@ 16.4 +/* 16.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 16.7 + * 16.8 + * This code is free software; you can redistribute it and/or modify it 16.9 + * under the terms of the GNU General Public License version 2 only, as 16.10 + * published by the Free Software Foundation. 16.11 + * 16.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 16.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16.15 + * version 2 for more details (a copy is included in the LICENSE file that 16.16 + * accompanied this code). 16.17 + * 16.18 + * You should have received a copy of the GNU General Public License version 16.19 + * 2 along with this work; if not, write to the Free Software Foundation, 16.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 16.21 + * 16.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 16.23 + * or visit www.oracle.com if you need additional information or have any 16.24 + * questions. 16.25 + */ 16.26 + 16.27 +package e; 16.28 + 16.29 +// use compact2 16.30 +public class E extends java.rmi.RemoteException { 16.31 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/test/tools/jdeps/f/F.java Thu Oct 17 13:19:48 2013 -0700 17.3 @@ -0,0 +1,31 @@ 17.4 +/* 17.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 17.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 17.7 + * 17.8 + * This code is free software; you can redistribute it and/or modify it 17.9 + * under the terms of the GNU General Public License version 2 only, as 17.10 + * published by the Free Software Foundation. 17.11 + * 17.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 17.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17.15 + * version 2 for more details (a copy is included in the LICENSE file that 17.16 + * accompanied this code). 17.17 + * 17.18 + * You should have received a copy of the GNU General Public License version 17.19 + * 2 along with this work; if not, write to the Free Software Foundation, 17.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17.21 + * 17.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 17.23 + * or visit www.oracle.com if you need additional information or have any 17.24 + * questions. 17.25 + */ 17.26 + 17.27 +package f; 17.28 + 17.29 +public class F { 17.30 + public F() { 17.31 + // jdk internal API 17.32 + sun.misc.Unsafe.getUnsafe(); 17.33 + } 17.34 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/test/tools/jdeps/g/G.java Thu Oct 17 13:19:48 2013 -0700 18.3 @@ -0,0 +1,29 @@ 18.4 +/* 18.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 18.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 18.7 + * 18.8 + * This code is free software; you can redistribute it and/or modify it 18.9 + * under the terms of the GNU General Public License version 2 only, as 18.10 + * published by the Free Software Foundation. 18.11 + * 18.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 18.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18.15 + * version 2 for more details (a copy is included in the LICENSE file that 18.16 + * accompanied this code). 18.17 + * 18.18 + * You should have received a copy of the GNU General Public License version 18.19 + * 2 along with this work; if not, write to the Free Software Foundation, 18.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18.21 + * 18.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 18.23 + * or visit www.oracle.com if you need additional information or have any 18.24 + * questions. 18.25 + */ 18.26 + 18.27 +package g; 18.28 + 18.29 +public class G { 18.30 + // Full JRE 18.31 + private static final boolean gui = java.beans.Beans.isGuiAvailable(); 18.32 +}
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/test/tools/jdeps/m/Bar.java Thu Oct 17 13:19:48 2013 -0700 19.3 @@ -0,0 +1,50 @@ 19.4 +/* 19.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 19.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 19.7 + * 19.8 + * This code is free software; you can redistribute it and/or modify it 19.9 + * under the terms of the GNU General Public License version 2 only, as 19.10 + * published by the Free Software Foundation. 19.11 + * 19.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 19.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19.15 + * version 2 for more details (a copy is included in the LICENSE file that 19.16 + * accompanied this code). 19.17 + * 19.18 + * You should have received a copy of the GNU General Public License version 19.19 + * 2 along with this work; if not, write to the Free Software Foundation, 19.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19.21 + * 19.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19.23 + * or visit www.oracle.com if you need additional information or have any 19.24 + * questions. 19.25 + */ 19.26 + 19.27 +package m; 19.28 + 19.29 +import java.util.*; 19.30 + 19.31 +@b.B 19.32 +public class Bar { 19.33 + public final Set<String> set = new HashSet<>(); 19.34 + protected d.D d; 19.35 + private f.F f; 19.36 + 19.37 + public Bar() { 19.38 + // compact3 19.39 + java.lang.management.ManagementFactory.getRuntimeMXBean(); 19.40 + } 19.41 + 19.42 + protected c.C c() { 19.43 + return new c.C(); 19.44 + } 19.45 + 19.46 + /* package private */ void setF(f.F o) { 19.47 + f = o; 19.48 + } 19.49 + 19.50 + private g.G g() { 19.51 + return new g.G(); 19.52 + } 19.53 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/test/tools/jdeps/m/Foo.java Thu Oct 17 13:19:48 2013 -0700 20.3 @@ -0,0 +1,33 @@ 20.4 +/* 20.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 20.7 + * 20.8 + * This code is free software; you can redistribute it and/or modify it 20.9 + * under the terms of the GNU General Public License version 2 only, as 20.10 + * published by the Free Software Foundation. 20.11 + * 20.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 20.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 20.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20.15 + * version 2 for more details (a copy is included in the LICENSE file that 20.16 + * accompanied this code). 20.17 + * 20.18 + * You should have received a copy of the GNU General Public License version 20.19 + * 2 along with this work; if not, write to the Free Software Foundation, 20.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20.21 + * 20.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20.23 + * or visit www.oracle.com if you need additional information or have any 20.24 + * questions. 20.25 + */ 20.26 + 20.27 +package m; 20.28 + 20.29 +public class Foo extends Bar implements c.I { 20.30 + public void foo() throws e.E { 20.31 + } 20.32 + public void run() { 20.33 + setF(new f.F()); 20.34 + } 20.35 +} 20.36 +
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/test/tools/jdeps/m/Gee.java Thu Oct 17 13:19:48 2013 -0700 21.3 @@ -0,0 +1,30 @@ 21.4 +/* 21.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 21.7 + * 21.8 + * This code is free software; you can redistribute it and/or modify it 21.9 + * under the terms of the GNU General Public License version 2 only, as 21.10 + * published by the Free Software Foundation. 21.11 + * 21.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 21.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 21.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21.15 + * version 2 for more details (a copy is included in the LICENSE file that 21.16 + * accompanied this code). 21.17 + * 21.18 + * You should have received a copy of the GNU General Public License version 21.19 + * 2 along with this work; if not, write to the Free Software Foundation, 21.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21.21 + * 21.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21.23 + * or visit www.oracle.com if you need additional information or have any 21.24 + * questions. 21.25 + */ 21.26 + 21.27 +package m; 21.28 + 21.29 + 21.30 +class Gee extends g.G { 21.31 + public sun.misc.Lock lock; 21.32 +} 21.33 +