mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 02:54:35 +02:00
8027481: jdeps to handle classes with the same package name and correct profile for javax.crypto.*
Reviewed-by: alanb, dfuchs
This commit is contained in:
parent
14d87a0e5a
commit
fa729039be
8 changed files with 458 additions and 160 deletions
|
@ -26,9 +26,11 @@ package com.sun.tools.jdeps;
|
||||||
|
|
||||||
import com.sun.tools.classfile.Dependency.Location;
|
import com.sun.tools.classfile.Dependency.Location;
|
||||||
import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
|
import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
|
@ -52,7 +54,7 @@ public class Analyzer {
|
||||||
|
|
||||||
private final Type type;
|
private final Type type;
|
||||||
private final Map<Archive, ArchiveDeps> results = new HashMap<>();
|
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
|
private final Archive NOT_FOUND
|
||||||
= new Archive(JdepsTask.getMessage("artifact.not.found"));
|
= new Archive(JdepsTask.getMessage("artifact.not.found"));
|
||||||
|
|
||||||
|
@ -69,6 +71,17 @@ public class Analyzer {
|
||||||
* Performs the dependency analysis on the given archives.
|
* Performs the dependency analysis on the given archives.
|
||||||
*/
|
*/
|
||||||
public void run(List<Archive> 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) {
|
for (Archive archive : archives) {
|
||||||
ArchiveDeps deps;
|
ArchiveDeps deps;
|
||||||
if (type == Type.CLASS || type == Type.VERBOSE) {
|
if (type == Type.CLASS || type == Type.VERBOSE) {
|
||||||
|
@ -76,33 +89,9 @@ public class Analyzer {
|
||||||
} else {
|
} else {
|
||||||
deps = new PackageVisitor(archive);
|
deps = new PackageVisitor(archive);
|
||||||
}
|
}
|
||||||
archive.visit(deps);
|
archive.visitDependences(deps);
|
||||||
results.put(archive, 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) {
|
public boolean hasDependences(Archive archive) {
|
||||||
|
@ -117,94 +106,143 @@ public class Analyzer {
|
||||||
* Visits the source archive to its destination archive of
|
* Visits the source archive to its destination archive of
|
||||||
* a recorded dependency.
|
* 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
|
* Visits a recorded dependency from origin to target which can be
|
||||||
* a fully-qualified classname, a package name, a profile or
|
* a fully-qualified classname, a package name, a profile or
|
||||||
* archive name depending on the Analyzer's type.
|
* 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) {
|
public void visitArchiveDependences(Archive source, Visitor v) {
|
||||||
ArchiveDeps r = results.get(source);
|
ArchiveDeps r = results.get(source);
|
||||||
for (Map.Entry<Archive,String> e : r.requireArchives.entrySet()) {
|
for (ArchiveDeps.Dep d: r.requireArchives()) {
|
||||||
v.visitArchiveDependence(r.archive, e.getKey(), e.getValue());
|
v.visitArchiveDependence(r.archive, d.archive, d.profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitDependences(Archive source, Visitor v) {
|
public void visitDependences(Archive source, Visitor v) {
|
||||||
ArchiveDeps r = results.get(source);
|
ArchiveDeps r = results.get(source);
|
||||||
for (String origin : r.deps.keySet()) {
|
for (Map.Entry<String, SortedSet<ArchiveDeps.Dep>> e: r.deps.entrySet()) {
|
||||||
for (String target : r.deps.get(origin)) {
|
String origin = e.getKey();
|
||||||
Archive archive = getArchive(target);
|
for (ArchiveDeps.Dep d: e.getValue()) {
|
||||||
assert source == getArchive(origin);
|
|
||||||
Profile profile = r.getTargetProfile(target);
|
|
||||||
|
|
||||||
// filter intra-dependency unless in verbose mode
|
// filter intra-dependency unless in verbose mode
|
||||||
if (type == Type.VERBOSE || archive != source) {
|
if (type == Type.VERBOSE || d.archive != source) {
|
||||||
v.visitDependence(origin, source, target, archive,
|
v.visitDependence(origin, source, d.target, d.archive, d.profile);
|
||||||
profile != null ? profile.toString() : "");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
private abstract class ArchiveDeps implements Archive.Visitor {
|
||||||
final Archive archive;
|
final Archive archive;
|
||||||
final Map<Archive,String> requireArchives;
|
final SortedMap<String, SortedSet<Dep>> deps;
|
||||||
final SortedMap<String, SortedSet<String>> deps;
|
|
||||||
Profile profile = null;
|
|
||||||
ArchiveDeps(Archive archive) {
|
ArchiveDeps(Archive archive) {
|
||||||
this.archive = archive;
|
this.archive = archive;
|
||||||
this.requireArchives = new HashMap<>();
|
|
||||||
this.deps = new TreeMap<>();
|
this.deps = new TreeMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(String loc) {
|
void add(String origin, String target, Archive targetArchive, String pkgName) {
|
||||||
Archive a = map.get(loc);
|
SortedSet<Dep> set = deps.get(origin);
|
||||||
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);
|
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
deps.put(origin, set = new TreeSet<>());
|
deps.put(origin, set = new TreeSet<>());
|
||||||
}
|
}
|
||||||
if (!set.contains(target)) {
|
Profile p = targetArchive instanceof JDKArchive
|
||||||
set.add(target);
|
? Profile.getProfile(pkgName) : null;
|
||||||
// find the corresponding profile
|
set.add(new Dep(target, targetArchive, p));
|
||||||
Profile p = getTargetProfile(target);
|
}
|
||||||
if (profile == null || (p != null && profile.profile < p.profile)) {
|
|
||||||
profile = 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 void visit(Location o, Location t);
|
||||||
public abstract Profile getTargetProfile(String target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ClassVisitor extends ArchiveDeps {
|
private class ClassVisitor extends ArchiveDeps {
|
||||||
ClassVisitor(Archive archive) {
|
ClassVisitor(Archive archive) {
|
||||||
super(archive);
|
super(archive);
|
||||||
}
|
}
|
||||||
public void visit(Location l) {
|
@Override
|
||||||
add(l.getClassName());
|
|
||||||
}
|
|
||||||
public void visit(Location o, Location t) {
|
public void visit(Location o, Location t) {
|
||||||
add(o.getClassName(), t.getClassName());
|
Archive targetArchive =
|
||||||
}
|
this.archive.getClasses().contains(t) ? this.archive : map.get(t);
|
||||||
public Profile getTargetProfile(String target) {
|
if (targetArchive == null) {
|
||||||
int i = target.lastIndexOf('.');
|
map.put(t, targetArchive = NOT_FOUND);
|
||||||
return (i > 0) ? Profile.getProfile(target.substring(0, i)) : null;
|
}
|
||||||
|
|
||||||
|
String origin = o.getClassName();
|
||||||
|
String target = t.getClassName();
|
||||||
|
add(origin, target, targetArchive, t.getPackageName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,18 +250,21 @@ public class Analyzer {
|
||||||
PackageVisitor(Archive archive) {
|
PackageVisitor(Archive archive) {
|
||||||
super(archive);
|
super(archive);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void visit(Location o, Location t) {
|
public void visit(Location o, Location t) {
|
||||||
add(packageOf(o), packageOf(t));
|
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());
|
||||||
}
|
}
|
||||||
public void visit(Location l) {
|
public String packageOf(Location o) {
|
||||||
add(packageOf(l));
|
String pkg = o.getPackageName();
|
||||||
}
|
|
||||||
private String packageOf(Location loc) {
|
|
||||||
String pkg = loc.getPackageName();
|
|
||||||
return pkg.isEmpty() ? "<unnamed>" : pkg;
|
return pkg.isEmpty() ? "<unnamed>" : pkg;
|
||||||
}
|
}
|
||||||
public Profile getTargetProfile(String target) {
|
|
||||||
return Profile.getProfile(target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ public class Archive {
|
||||||
deps.put(origin, set);
|
deps.put(origin, set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addClass(Location origin, Location target) {
|
public void addClass(Location origin, Location target) {
|
||||||
Set<Location> set = deps.get(origin);
|
Set<Location> set = deps.get(origin);
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
|
@ -76,21 +77,27 @@ public class Archive {
|
||||||
set.add(target);
|
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()) {
|
for (Map.Entry<Location,Set<Location>> e: deps.entrySet()) {
|
||||||
v.visit(e.getKey());
|
|
||||||
for (Location target : e.getValue()) {
|
for (Location target : e.getValue()) {
|
||||||
v.visit(e.getKey(), target);
|
v.visit(e.getKey(), target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String getPathName() {
|
||||||
return path != null ? path.toString() : filename;
|
return path != null ? path.toString() : filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
interface Visitor {
|
interface Visitor {
|
||||||
void visit(Location loc);
|
|
||||||
void visit(Location origin, Location target);
|
void visit(Location origin, Location target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,6 +190,11 @@ class JdepsTask {
|
||||||
task.options.fullVersion = true;
|
task.options.fullVersion = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
new HiddenOption(false, "-showlabel") {
|
||||||
|
void process(JdepsTask task, String opt, String arg) {
|
||||||
|
task.options.showLabel = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
new HiddenOption(true, "-depth") {
|
new HiddenOption(true, "-depth") {
|
||||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||||
try {
|
try {
|
||||||
|
@ -279,12 +284,21 @@ class JdepsTask {
|
||||||
|
|
||||||
private void generateDotFiles(Path dir, Analyzer analyzer) throws IOException {
|
private void generateDotFiles(Path dir, Analyzer analyzer) throws IOException {
|
||||||
Path summary = dir.resolve("summary.dot");
|
Path summary = dir.resolve("summary.dot");
|
||||||
try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary));
|
boolean verbose = options.verbose == Analyzer.Type.VERBOSE;
|
||||||
DotFileFormatter formatter = new DotFileFormatter(sw, "summary")) {
|
DotGraph<?> graph = verbose ? new DotSummaryForPackage()
|
||||||
for (Archive archive : sourceLocations) {
|
: new DotSummaryForArchive();
|
||||||
analyzer.visitArchiveDependences(archive, formatter);
|
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) {
|
if (options.verbose != Analyzer.Type.SUMMARY) {
|
||||||
for (Archive archive : sourceLocations) {
|
for (Archive archive : sourceLocations) {
|
||||||
if (analyzer.hasDependences(archive)) {
|
if (analyzer.hasDependences(archive)) {
|
||||||
|
@ -365,17 +379,16 @@ class JdepsTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sourceLocations.addAll(archives);
|
||||||
|
|
||||||
List<Archive> classpaths = new ArrayList<>(); // for class file lookup
|
List<Archive> classpaths = new ArrayList<>(); // for class file lookup
|
||||||
|
classpaths.addAll(getClassPathArchives(options.classpath));
|
||||||
if (options.includePattern != null) {
|
if (options.includePattern != null) {
|
||||||
archives.addAll(getClassPathArchives(options.classpath));
|
archives.addAll(classpaths);
|
||||||
} else {
|
|
||||||
classpaths.addAll(getClassPathArchives(options.classpath));
|
|
||||||
}
|
}
|
||||||
classpaths.addAll(PlatformClassPath.getArchives());
|
classpaths.addAll(PlatformClassPath.getArchives());
|
||||||
|
|
||||||
// add all archives to the source locations for reporting
|
// add all classpath archives to the source locations for reporting
|
||||||
sourceLocations.addAll(archives);
|
|
||||||
sourceLocations.addAll(classpaths);
|
sourceLocations.addAll(classpaths);
|
||||||
|
|
||||||
// Work queue of names of classfiles to be searched.
|
// Work queue of names of classfiles to be searched.
|
||||||
|
@ -557,6 +570,7 @@ class JdepsTask {
|
||||||
boolean showSummary;
|
boolean showSummary;
|
||||||
boolean wildcard;
|
boolean wildcard;
|
||||||
boolean apiOnly;
|
boolean apiOnly;
|
||||||
|
boolean showLabel;
|
||||||
String dotOutputDir;
|
String dotOutputDir;
|
||||||
String classpath = "";
|
String classpath = "";
|
||||||
int depth = 1;
|
int depth = 1;
|
||||||
|
@ -627,16 +641,34 @@ class JdepsTask {
|
||||||
return result;
|
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
|
* Returns the profile name or "JDK internal API" for JDK archive;
|
||||||
* internal JRE classes. It returns empty string for SE API.
|
* otherwise empty string.
|
||||||
*/
|
*/
|
||||||
private static String getArchiveName(Archive source, String profile) {
|
private String profileName(Archive archive, Profile profile) {
|
||||||
String name = source.getFileName();
|
if (archive instanceof JDKArchive) {
|
||||||
if (source instanceof JDKArchive)
|
return Objects.toString(profile, "JDK internal API");
|
||||||
return profile.isEmpty() ? "JDK internal API (" + name + ")" : "";
|
} else {
|
||||||
return name;
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RawOutputFormatter implements Analyzer.Visitor {
|
class RawOutputFormatter implements Analyzer.Visitor {
|
||||||
|
@ -648,21 +680,18 @@ class JdepsTask {
|
||||||
private String pkg = "";
|
private String pkg = "";
|
||||||
@Override
|
@Override
|
||||||
public void visitDependence(String origin, Archive source,
|
public void visitDependence(String origin, Archive source,
|
||||||
String target, Archive archive, String profile) {
|
String target, Archive archive, Profile profile) {
|
||||||
if (!origin.equals(pkg)) {
|
if (!origin.equals(pkg)) {
|
||||||
pkg = origin;
|
pkg = origin;
|
||||||
writer.format(" %s (%s)%n", origin, source.getFileName());
|
writer.format(" %s (%s)%n", origin, source.getFileName());
|
||||||
}
|
}
|
||||||
String name = (options.showProfile && !profile.isEmpty())
|
writer.format(" -> %-50s %s%n", target, getProfileArchiveInfo(archive, profile));
|
||||||
? profile
|
|
||||||
: getArchiveName(archive, profile);
|
|
||||||
writer.format(" -> %-50s %s%n", target, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitArchiveDependence(Archive origin, Archive target, String profile) {
|
public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
|
||||||
writer.format("%s -> %s", origin, target);
|
writer.format("%s -> %s", origin.getPathName(), target.getPathName());
|
||||||
if (options.showProfile && !profile.isEmpty()) {
|
if (options.showProfile && profile != null) {
|
||||||
writer.format(" (%s)%n", profile);
|
writer.format(" (%s)%n", profile);
|
||||||
} else {
|
} else {
|
||||||
writer.format("%n");
|
writer.format("%n");
|
||||||
|
@ -670,19 +699,14 @@ class JdepsTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DotFileFormatter implements Analyzer.Visitor, AutoCloseable {
|
class DotFileFormatter extends DotGraph<String> implements AutoCloseable {
|
||||||
private final PrintWriter writer;
|
private final PrintWriter writer;
|
||||||
private final String name;
|
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) {
|
DotFileFormatter(PrintWriter writer, Archive archive) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
this.name = archive.getFileName();
|
this.name = archive.getFileName();
|
||||||
writer.format("digraph \"%s\" {%n", name);
|
writer.format("digraph \"%s\" {%n", name);
|
||||||
writer.format(" // Path: %s%n", archive.toString());
|
writer.format(" // Path: %s%n", archive.getPathName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -690,39 +714,169 @@ class JdepsTask {
|
||||||
writer.println("}");
|
writer.println("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Set<String> edges = new HashSet<>();
|
|
||||||
private String node = "";
|
|
||||||
@Override
|
@Override
|
||||||
public void visitDependence(String origin, Archive source,
|
public void visitDependence(String origin, Archive source,
|
||||||
String target, Archive archive, String profile) {
|
String target, Archive archive, Profile profile) {
|
||||||
if (!node.equals(origin)) {
|
|
||||||
edges.clear();
|
|
||||||
node = origin;
|
|
||||||
}
|
|
||||||
// if -P option is specified, package name -> profile will
|
// if -P option is specified, package name -> profile will
|
||||||
// be shown and filter out multiple same edges.
|
// be shown and filter out multiple same edges.
|
||||||
if (!edges.contains(target)) {
|
String name = getProfileArchiveInfo(archive, profile);
|
||||||
StringBuilder sb = new StringBuilder();
|
writeEdge(writer, new Edge(origin, target, getProfileArchiveInfo(archive, profile)));
|
||||||
String name = options.showProfile && !profile.isEmpty()
|
}
|
||||||
? profile
|
@Override
|
||||||
: getArchiveName(archive, profile);
|
public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
|
||||||
writer.format(" %-50s -> %s;%n",
|
throw new UnsupportedOperationException();
|
||||||
String.format("\"%s\"", origin),
|
}
|
||||||
name.isEmpty() ? String.format("\"%s\"", target)
|
}
|
||||||
: String.format("\"%s (%s)\"", target, name));
|
|
||||||
edges.add(target);
|
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
|
@Override
|
||||||
public void visitArchiveDependence(Archive origin, Archive target, String profile) {
|
public void visitDependence(String origin, Archive source,
|
||||||
String name = options.showProfile && !profile.isEmpty()
|
String target, Archive archive, Profile profile) {
|
||||||
? profile : "";
|
// add a package dependency edge
|
||||||
writer.format(" %-30s -> \"%s\";%n",
|
String from = packageOf(origin);
|
||||||
String.format("\"%s\"", origin.getFileName()),
|
String to = packageOf(target);
|
||||||
name.isEmpty()
|
Edge e = addEdge(from, to, getProfileArchiveInfo(archive, profile));
|
||||||
? target.getFileName()
|
|
||||||
: String.format("%s (%s)", target.getFileName(), name));
|
// 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, 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,8 +81,12 @@ enum Profile {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class PackageToProfile {
|
static class PackageToProfile {
|
||||||
|
static String[] JAVAX_CRYPTO_PKGS = new String[] {
|
||||||
|
"javax.crypto",
|
||||||
|
"javax.crypto.interfaces",
|
||||||
|
"javax.crypto.spec"
|
||||||
|
};
|
||||||
static Map<String, Profile> map = initProfiles();
|
static Map<String, Profile> map = initProfiles();
|
||||||
|
|
||||||
private static Map<String, Profile> initProfiles() {
|
private static Map<String, Profile> initProfiles() {
|
||||||
try {
|
try {
|
||||||
String profilesProps = System.getProperty("jdeps.profiles");
|
String profilesProps = System.getProperty("jdeps.profiles");
|
||||||
|
@ -103,6 +107,9 @@ enum Profile {
|
||||||
findProfile(cf);
|
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) {
|
} catch (IOException | ConstantPoolException e) {
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -23,9 +23,9 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8003562 8005428 8015912
|
* @bug 8003562 8005428 8015912 8027481
|
||||||
* @summary Basic tests for jdeps tool
|
* @summary Basic tests for jdeps tool
|
||||||
* @build Test p.Foo
|
* @build Test p.Foo p.Bar javax.activity.NotCompactProfile
|
||||||
* @run main Basic
|
* @run main Basic
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -33,10 +33,12 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.*;
|
import java.util.regex.*;
|
||||||
|
import static java.nio.file.StandardCopyOption.*;
|
||||||
|
|
||||||
public class Basic {
|
public class Basic {
|
||||||
private static boolean symbolFileExist = initProfiles();
|
private static boolean symbolFileExist = initProfiles();
|
||||||
|
@ -74,23 +76,25 @@ public class Basic {
|
||||||
new String[] {"java.lang", "p"},
|
new String[] {"java.lang", "p"},
|
||||||
new String[] {"compact1", "not found"});
|
new String[] {"compact1", "not found"});
|
||||||
// test a directory
|
// test a directory
|
||||||
|
// also test non-SE javax.activity class dependency
|
||||||
test(new File(testDir, "p"),
|
test(new File(testDir, "p"),
|
||||||
new String[] {"java.lang", "java.util", "java.lang.management"},
|
new String[] {"java.lang", "java.util", "java.lang.management", "javax.activity", "javax.crypto"},
|
||||||
new String[] {"compact1", "compact1", "compact3"});
|
new String[] {"compact1", "compact1", "compact3", testDir.getName(), "compact1"},
|
||||||
|
new String[] {"-classpath", testDir.getPath()});
|
||||||
// test class-level dependency output
|
// test class-level dependency output
|
||||||
test(new File(testDir, "Test.class"),
|
test(new File(testDir, "Test.class"),
|
||||||
new String[] {"java.lang.Object", "java.lang.String", "p.Foo"},
|
new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
|
||||||
new String[] {"compact1", "compact1", "not found"},
|
new String[] {"compact1", "compact1", "not found", "not found"},
|
||||||
new String[] {"-verbose:class"});
|
new String[] {"-verbose:class"});
|
||||||
// test -p option
|
// test -p option
|
||||||
test(new File(testDir, "Test.class"),
|
test(new File(testDir, "Test.class"),
|
||||||
new String[] {"p.Foo"},
|
new String[] {"p.Foo", "p.Bar"},
|
||||||
new String[] {"not found"},
|
new String[] {"not found", "not found"},
|
||||||
new String[] {"-verbose:class", "-p", "p"});
|
new String[] {"-verbose:class", "-p", "p"});
|
||||||
// test -e option
|
// test -e option
|
||||||
test(new File(testDir, "Test.class"),
|
test(new File(testDir, "Test.class"),
|
||||||
new String[] {"p.Foo"},
|
new String[] {"p.Foo", "p.Bar"},
|
||||||
new String[] {"not found"},
|
new String[] {"not found", "not found"},
|
||||||
new String[] {"-verbose:class", "-e", "p\\..*"});
|
new String[] {"-verbose:class", "-e", "p\\..*"});
|
||||||
test(new File(testDir, "Test.class"),
|
test(new File(testDir, "Test.class"),
|
||||||
new String[] {"java.lang"},
|
new String[] {"java.lang"},
|
||||||
|
@ -99,13 +103,34 @@ public class Basic {
|
||||||
// test -classpath and -include options
|
// test -classpath and -include options
|
||||||
test(null,
|
test(null,
|
||||||
new String[] {"java.lang", "java.util",
|
new String[] {"java.lang", "java.util",
|
||||||
"java.lang.management"},
|
"java.lang.management", "javax.crypto"},
|
||||||
new String[] {"compact1", "compact1", "compact3"},
|
new String[] {"compact1", "compact1", "compact3", "compact1"},
|
||||||
new String[] {"-classpath", testDir.getPath(), "-include", "p.+|Test.class"});
|
new String[] {"-classpath", testDir.getPath(), "-include", "p.+|Test.class"});
|
||||||
test(new File(testDir, "Test.class"),
|
test(new File(testDir, "Test.class"),
|
||||||
new String[] {"java.lang.Object", "java.lang.String", "p.Foo"},
|
new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
|
||||||
new String[] {"compact1", "compact1", testDir.getName()},
|
new String[] {"compact1", "compact1", testDir.getName(), testDir.getName()},
|
||||||
new String[] {"-v", "-classpath", testDir.getPath(), "Test.class"});
|
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;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +173,7 @@ public class Basic {
|
||||||
// Use the linePattern to break the given String into lines, applying
|
// Use the linePattern to break the given String into lines, applying
|
||||||
// the pattern to each line to see if we have a match
|
// the pattern to each line to see if we have a match
|
||||||
private static Map<String,String> findDeps(String out) {
|
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 lm = linePattern.matcher(out); // Line matcher
|
||||||
Matcher pm = null; // Pattern matcher
|
Matcher pm = null; // Pattern matcher
|
||||||
int lines = 0;
|
int lines = 0;
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -24,6 +24,7 @@
|
||||||
public class Test {
|
public class Test {
|
||||||
public void test() {
|
public void test() {
|
||||||
p.Foo f = new p.Foo();
|
p.Foo f = new p.Foo();
|
||||||
|
p.Bar b = new p.Bar();
|
||||||
}
|
}
|
||||||
private String name() {
|
private String name() {
|
||||||
return "this test";
|
return "this test";
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
33
langtools/test/tools/jdeps/p/Bar.java
Normal file
33
langtools/test/tools/jdeps/p/Bar.java
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue