# HG changeset patch # User mchung # Date 1405705421 25200 # Node ID a51b7fd0543b4254cfcce3839102aa06030962b5 # Parent 1e39ae45d8acdb04a61f03906dabf54874208455 8050804: (jdeps) Recommend supported API to replace use of JDK internal API Reviewed-by: dfuchs diff -r 1e39ae45d8ac -r a51b7fd0543b src/share/classes/com/sun/tools/jdeps/Analyzer.java --- a/src/share/classes/com/sun/tools/jdeps/Analyzer.java Thu Jul 17 15:23:08 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdeps/Analyzer.java Fri Jul 18 10:43:41 2014 -0700 @@ -114,6 +114,11 @@ return false; } + public Set dependences(Archive source) { + ArchiveDeps result = results.get(source); + return result.targetDependences(); + } + public interface Visitor { /** * Visits a recorded dependency from origin to target which can be @@ -179,6 +184,14 @@ return deps; } + Set targetDependences() { + Set targets = new HashSet<>(); + for (Dep d : deps) { + targets.add(d.target()); + } + return targets; + } + Set requires() { return requires; } diff -r 1e39ae45d8ac -r a51b7fd0543b src/share/classes/com/sun/tools/jdeps/JdepsTask.java --- a/src/share/classes/com/sun/tools/jdeps/JdepsTask.java Thu Jul 17 15:23:08 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdeps/JdepsTask.java Fri Jul 18 10:43:41 2014 -0700 @@ -236,6 +236,11 @@ task.options.showLabel = true; } }, + new HiddenOption(false, "-q", "-quiet") { + void process(JdepsTask task, String opt, String arg) { + task.options.nowarning = true; + } + }, new HiddenOption(true, "-depth") { void process(JdepsTask task, String opt, String arg) throws BadArgs { try { @@ -249,7 +254,7 @@ private static final String PROGNAME = "jdeps"; private final Options options = new Options(); - private final List classes = new ArrayList(); + private final List classes = new ArrayList<>(); private PrintWriter log; void setLog(PrintWriter out) { @@ -320,7 +325,9 @@ Analyzer analyzer = new Analyzer(options.verbose, new Analyzer.Filter() { @Override - public boolean accepts(Location origin, Archive originArchive, Location target, Archive targetArchive) { + public boolean accepts(Location origin, Archive originArchive, + Location target, Archive targetArchive) + { if (options.findJDKInternals) { // accepts target that is JDK class but not exported return isJDKArchive(targetArchive) && @@ -344,6 +351,10 @@ } else { printRawOutput(log, analyzer); } + + if (options.findJDKInternals && !options.nowarning) { + showReplacements(analyzer); + } return true; } @@ -693,6 +704,7 @@ boolean apiOnly; boolean showLabel; boolean findJDKInternals; + boolean nowarning; // default is to show package-level dependencies // and filter references from same package Analyzer.Type verbose = PACKAGE; @@ -709,6 +721,7 @@ private static class ResourceBundleHelper { static final ResourceBundle versionRB; static final ResourceBundle bundle; + static final ResourceBundle jdkinternals; static { Locale locale = Locale.getDefault(); @@ -722,6 +735,11 @@ } catch (MissingResourceException e) { throw new InternalError("version.resource.missing"); } + try { + jdkinternals = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdkinternals"); + } catch (MissingResourceException e) { + throw new InternalError("Cannot find jdkinternals resource bundle"); + } } } @@ -935,4 +953,50 @@ } return Profile.getProfile(pn); } + + /** + * Returns the recommended replacement API for the given classname; + * or return null if replacement API is not known. + */ + private String replacementFor(String cn) { + String name = cn; + String value = null; + while (value == null && name != null) { + try { + value = ResourceBundleHelper.jdkinternals.getString(name); + } catch (MissingResourceException e) { + // go up one subpackage level + int i = name.lastIndexOf('.'); + name = i > 0 ? name.substring(0, i) : null; + } + } + return value; + }; + + private void showReplacements(Analyzer analyzer) { + Map jdkinternals = new TreeMap<>(); + boolean useInternals = false; + for (Archive source : sourceLocations) { + useInternals = useInternals || analyzer.hasDependences(source); + for (String cn : analyzer.dependences(source)) { + String repl = replacementFor(cn); + if (repl != null && !jdkinternals.containsKey(cn)) { + jdkinternals.put(cn, repl); + } + } + } + if (useInternals) { + log.println(); + warning("warn.replace.useJDKInternals", getMessage("jdeps.wiki.url")); + } + if (!jdkinternals.isEmpty()) { + log.println(); + log.format("%-40s %s%n", "JDK Internal API", "Suggested Replacement"); + log.format("%-40s %s%n", "----------------", "---------------------"); + for (Map.Entry e : jdkinternals.entrySet()) { + log.format("%-40s %s%n", e.getKey(), e.getValue()); + } + } + + } } diff -r 1e39ae45d8ac -r a51b7fd0543b src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties --- a/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Thu Jul 17 15:23:08 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Fri Jul 18 10:43:41 2014 -0700 @@ -93,5 +93,12 @@ err.invalid.path=invalid path: {0} warn.invalid.arg=Invalid classname or pathname not exist: {0} warn.split.package=package {0} defined in {1} {2} +warn.replace.useJDKInternals=\ +JDK internal APIs are unsupported and private to JDK implementation that are\n\ +subject to be removed or changed incompatibly and could break your application.\n\ +Please modify your code to eliminate dependency on any JDK internal APIs.\n\ +For the most recent update on JDK internal API replacements, please check:\n\ +{0} artifact.not.found=not found +jdeps.wiki.url=https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool diff -r 1e39ae45d8ac -r a51b7fd0543b src/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties Fri Jul 18 10:43:41 2014 -0700 @@ -0,0 +1,22 @@ +// No translation needed +com.sun.crypto.provider.SunJCE=Use java.security.Security.getProvider(provider-name) @since 1.3 +com.sun.image.codec=Use javax.imageio @since 1.4 +com.sun.org.apache.xml.internal.security=Use java.xml.crypto @since 1.6 +com.sun.org.apache.xml.internal.security.utils.Base64=Use java.util.Base64 @since 1.8 +com.sun.net.ssl=Use javax.net.ssl @since 1.4 +com.sun.net.ssl.internal.ssl.Provider=Use java.security.Security.getProvider(provider-name) @since 1.3 +com.sun.rowset=Use javax.sql.rowset.RowSetProvider @since 1.7 +com.sun.tools.javac.tree=Use com.sun.source @since 1.6 +com.sun.tools.javac=Use javax.tools and javax.lang.model @since 1.6 +sun.awt.image.codec=Use javax.imageio @since 1.4 +sun.misc.BASE64Encoder=Use java.util.Base64 @since 1.8 +sun.misc.BASE64Decoder=Use java.util.Base64 @since 1.8 +sun.misc.Cleaner=Use java.lang.ref.PhantomReference @since 1.2 +sun.misc.Service=Use java.util.ServiceLoader @since 1.6 +sun.security.action=Use java.security.PrivilegedAction @since 1.1 +sun.security.krb5=Use com.sun.security.jgss +sun.security.provider.PolicyFile=Use java.security.Policy.getInstance("JavaPolicy", new URIParameter(uri)) @since 1.6 +sun.security.provider.Sun=Use java.security.Security.getProvider(provider-name) @since 1.3 +sun.security.util.SecurityConstants=Use appropriate java.security.Permission subclass @since 1.1 +sun.security.x509.X500Name=Use javax.security.auth.x500.X500Principal @since 1.4 +sun.tools.jar=Use java.util.jar or jar tool @since 1.2 diff -r 1e39ae45d8ac -r a51b7fd0543b test/tools/jdeps/APIDeps.java --- a/test/tools/jdeps/APIDeps.java Thu Jul 17 15:23:08 2014 -0700 +++ b/test/tools/jdeps/APIDeps.java Fri Jul 18 10:43:41 2014 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 8015912 8029216 8048063 + * @bug 8015912 8029216 8048063 8050804 * @summary Test -apionly and -jdkinternals options * @build m.Bar m.Foo m.Gee b.B c.C c.I d.D e.E f.F g.G * @run main APIDeps