8176329: jdeps to detect MR jar file and output a warning jdk8u141-b08

Thu, 27 Apr 2017 16:18:18 -0700

author
bchristi
date
Thu, 27 Apr 2017 16:18:18 -0700
changeset 3389
e2abef6f10b9
parent 3388
e4d2d5a018e3
child 3390
1df48afb34a0

8176329: jdeps to detect MR jar file and output a warning
Reviewed-by: mchung

src/share/classes/com/sun/tools/jdeps/ClassFileReader.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/JdepsTask.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties file | annotate | diff | comparison | revisions
test/tools/jdeps/MRJarWarning.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Mon May 01 10:55:28 2017 -0700
     1.2 +++ b/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Thu Apr 27 16:18:18 2017 -0700
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -34,8 +34,10 @@
    1.11  import java.nio.file.SimpleFileVisitor;
    1.12  import java.nio.file.attribute.BasicFileAttributes;
    1.13  import java.util.*;
    1.14 +import java.util.jar.Attributes;
    1.15  import java.util.jar.JarEntry;
    1.16  import java.util.jar.JarFile;
    1.17 +import java.util.jar.Manifest;
    1.18  
    1.19  /**
    1.20   * ClassFileReader reads ClassFile(s) of a given path that can be
    1.21 @@ -154,6 +156,8 @@
    1.22          }
    1.23      }
    1.24  
    1.25 +    public boolean isMultiReleaseJar() throws IOException { return false; }
    1.26 +
    1.27      public String toString() {
    1.28          return path.toString();
    1.29      }
    1.30 @@ -290,6 +294,16 @@
    1.31                  }
    1.32              };
    1.33          }
    1.34 +
    1.35 +        @Override
    1.36 +        public boolean isMultiReleaseJar() throws IOException {
    1.37 +            Manifest mf = this.jarfile.getManifest();
    1.38 +            if (mf != null) {
    1.39 +                Attributes atts = mf.getMainAttributes();
    1.40 +                return "true".equalsIgnoreCase(atts.getValue("Multi-Release"));
    1.41 +            }
    1.42 +            return false;
    1.43 +        }
    1.44      }
    1.45  
    1.46      class JarFileIterator implements Iterator<ClassFile> {
     2.1 --- a/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Mon May 01 10:55:28 2017 -0700
     2.2 +++ b/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu Apr 27 16:18:18 2017 -0700
     2.3 @@ -1,5 +1,5 @@
     2.4  /*
     2.5 - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
     2.6 + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
     2.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.8   *
     2.9   * This code is free software; you can redistribute it and/or modify it
    2.10 @@ -515,6 +515,13 @@
    2.11          // add all classpath archives to the source locations for reporting
    2.12          sourceLocations.addAll(classpaths);
    2.13  
    2.14 +        // warn about Multi-Release jars
    2.15 +        for (Archive a : sourceLocations) {
    2.16 +            if (a.reader().isMultiReleaseJar()) {
    2.17 +                warning("warn.mrjar.usejdk9", a.getPathName());
    2.18 +            }
    2.19 +        }
    2.20 +
    2.21          // Work queue of names of classfiles to be searched.
    2.22          // Entries will be unique, and for classes that do not yet have
    2.23          // dependencies in the results map.
     3.1 --- a/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Mon May 01 10:55:28 2017 -0700
     3.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Thu Apr 27 16:18:18 2017 -0700
     3.3 @@ -99,6 +99,10 @@
     3.4  Please modify your code to eliminate dependency on any JDK internal APIs.\n\
     3.5  For the most recent update on JDK internal API replacements, please check:\n\
     3.6  {0}
     3.7 +warn.mrjar.usejdk9=\
     3.8 +{0} is a multi-release jar file.\n\
     3.9 +All versioned entries are analyzed. To analyze the entries for a specific\n\
    3.10 +version, use a newer version of jdeps (JDK 9 or later) \"--multi-release\" option.
    3.11  
    3.12  artifact.not.found=not found
    3.13  jdeps.wiki.url=https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool
     4.1 --- a/src/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties	Mon May 01 10:55:28 2017 -0700
     4.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties	Thu Apr 27 16:18:18 2017 -0700
     4.3 @@ -1,22 +1,45 @@
     4.4  // No translation needed
     4.5  com.sun.crypto.provider.SunJCE=Use java.security.Security.getProvider(provider-name) @since 1.3
     4.6 -com.sun.image.codec=Use javax.imageio @since 1.4
     4.7  com.sun.org.apache.xml.internal.security=Use java.xml.crypto @since 1.6
     4.8  com.sun.org.apache.xml.internal.security.utils.Base64=Use java.util.Base64 @since 1.8
     4.9 +com.sun.org.apache.xml.internal.resolver=Use javax.xml.catalog @since 9
    4.10  com.sun.net.ssl=Use javax.net.ssl @since 1.4
    4.11  com.sun.net.ssl.internal.ssl.Provider=Use java.security.Security.getProvider(provider-name) @since 1.3
    4.12  com.sun.rowset=Use javax.sql.rowset.RowSetProvider @since 1.7
    4.13 +com.sun.tools.doclets.standard=Use jdk.javadoc.doclets.StandardDoclet @since 9.
    4.14  com.sun.tools.javac.tree=Use com.sun.source @since 1.6
    4.15  com.sun.tools.javac=Use javax.tools and javax.lang.model @since 1.6
    4.16 -sun.awt.image.codec=Use javax.imageio @since 1.4
    4.17 -sun.misc.BASE64Encoder=Use java.util.Base64 @since 1.8
    4.18 -sun.misc.BASE64Decoder=Use java.util.Base64 @since 1.8
    4.19 -sun.misc.Cleaner=Use java.lang.ref.PhantomReference @since 1.2
    4.20 -sun.misc.Service=Use java.util.ServiceLoader @since 1.6
    4.21 +java.awt.peer=Should not use. See https://bugs.openjdk.java.net/browse/JDK-8037739
    4.22 +java.awt.dnd.peer=Should not use. See https://bugs.openjdk.java.net/browse/JDK-8037739
    4.23 +jdk.internal.ref.Cleaner=Use java.lang.ref.PhantomReference @since 1.2 or java.lang.ref.Cleaner @since 9
    4.24 +sun.awt.CausedFocusEvent=Use java.awt.event.FocusEvent::getCause @since 9
    4.25 +sun.font.FontUtilities=See java.awt.Font.textRequiresLayout @since 9
    4.26 +sun.reflect.Reflection=See http://openjdk.java.net/jeps/260
    4.27 +sun.reflect.ReflectionFactory=See http://openjdk.java.net/jeps/260
    4.28 +sun.misc.Unsafe=See http://openjdk.java.net/jeps/260
    4.29 +sun.misc.Signal=See http://openjdk.java.net/jeps/260
    4.30 +sun.misc.SignalHandler=See http://openjdk.java.net/jeps/260
    4.31  sun.security.action=Use java.security.PrivilegedAction @since 1.1
    4.32  sun.security.krb5=Use com.sun.security.jgss
    4.33  sun.security.provider.PolicyFile=Use java.security.Policy.getInstance("JavaPolicy", new URIParameter(uri)) @since 1.6
    4.34  sun.security.provider.Sun=Use java.security.Security.getProvider(provider-name) @since 1.3
    4.35 +sun.security.util.HostnameChecker=Use javax.net.ssl.SSLParameters.setEndpointIdentificationAlgorithm("HTTPS") @since 1.7\n\
    4.36 +or javax.net.ssl.HttpsURLConnection.setHostnameVerifier() @since 1.4
    4.37  sun.security.util.SecurityConstants=Use appropriate java.security.Permission subclass @since 1.1
    4.38  sun.security.x509.X500Name=Use javax.security.auth.x500.X500Principal @since 1.4
    4.39 -sun.tools.jar=Use java.util.jar or jar tool @since 1.2
    4.40 +sun.tools.jar=Use java.util.jar @since 1.2
    4.41 +sun.tools.jar.Main=Use java.util.spi.ToolProvider @since 9
    4.42 +# Internal APIs removed in JDK 9
    4.43 +com.apple.eawt=Use java.awt.Desktop @since 9.  See http://openjdk.java.net/jeps/272
    4.44 +com.apple.concurrent=Removed in JDK 9. See https://bugs.openjdk.java.net/browse/JDK-8148187
    4.45 +com.sun.image.codec.jpeg=Use javax.imageio @since 1.4
    4.46 +sun.awt.image.codec=Use javax.imageio @since 1.4
    4.47 +sun.misc.BASE64Encoder=Use java.util.Base64 @since 1.8
    4.48 +sun.misc.BASE64Decoder=Use java.util.Base64 @since 1.8
    4.49 +sun.misc.ClassLoaderUtil=Use java.net.URLClassLoader.close() @since 1.7
    4.50 +sun.misc.Cleaner=Use java.lang.ref.PhantomReference @since 1.2 or java.lang.ref.Cleaner @since 9.\n\
    4.51 +See http://openjdk.java.net/jeps/260.
    4.52 +sun.misc.Service=Use java.util.ServiceLoader @since 1.6
    4.53 +sun.misc=Removed in JDK 9. See http://openjdk.java.net/jeps/260
    4.54 +sun.reflect=Removed in JDK 9. See http://openjdk.java.net/jeps/260
    4.55 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/tools/jdeps/MRJarWarning.java	Thu Apr 27 16:18:18 2017 -0700
     5.3 @@ -0,0 +1,169 @@
     5.4 +/*
     5.5 + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + */
    5.26 +
    5.27 +/*
    5.28 + * @test
    5.29 + * @bug 8176329
    5.30 + * @summary Test for jdeps warning when it encounters a multi-release jar
    5.31 + * @run testng MRJarWarning
    5.32 + */
    5.33 +
    5.34 +import java.io.IOException;
    5.35 +import java.io.OutputStream;
    5.36 +import java.io.PrintWriter;
    5.37 +import java.io.StringWriter;
    5.38 +import java.nio.file.Files;
    5.39 +import java.nio.file.Path;
    5.40 +import java.nio.file.Paths;
    5.41 +import java.util.Arrays;
    5.42 +import java.util.Collections;
    5.43 +import java.util.List;
    5.44 +import java.util.Locale;
    5.45 +import java.util.jar.Attributes;
    5.46 +import java.util.jar.JarEntry;
    5.47 +import java.util.jar.JarOutputStream;
    5.48 +import java.util.jar.Manifest;
    5.49 +import org.testng.Assert;
    5.50 +import org.testng.annotations.BeforeSuite;
    5.51 +import org.testng.annotations.DataProvider;
    5.52 +import org.testng.annotations.Test;
    5.53 +
    5.54 +public class MRJarWarning {
    5.55 +    private static final String WARNING = " is a multi-release jar file";
    5.56 +    private static final String MRJAR_ATTR = "Multi-Release";
    5.57 +
    5.58 +    Path mrjar1;
    5.59 +    Path mrjar2;
    5.60 +    Path nonMRjar;
    5.61 +    Path mrjarAllCaps;
    5.62 +
    5.63 +    private Attributes defaultAttributes;
    5.64 +
    5.65 +    @BeforeSuite
    5.66 +    public void setup() throws IOException {
    5.67 +        defaultAttributes = new Attributes();
    5.68 +        defaultAttributes.putValue("Manifest-Version", "1.0");
    5.69 +        defaultAttributes.putValue("Created-By", "1.8.0-internal");
    5.70 +
    5.71 +        mrjar1   = Paths.get("mrjar1.jar");
    5.72 +        mrjar2   = Paths.get("mrjar2.jar");
    5.73 +        nonMRjar = Paths.get("nonMRjar.jar");
    5.74 +        mrjarAllCaps = Paths.get("mrjarAllCaps.jar");
    5.75 +
    5.76 +        Attributes mrJarAttrs = new Attributes(defaultAttributes);
    5.77 +        mrJarAttrs.putValue(MRJAR_ATTR, "true");
    5.78 +
    5.79 +        build(mrjar1, mrJarAttrs);
    5.80 +        build(mrjar2, mrJarAttrs);
    5.81 +        build(nonMRjar, defaultAttributes);
    5.82 +
    5.83 +        // JEP 238 - "Multi-Release JAR Files" states that the attribute name
    5.84 +        // and value are case insensitive.  Try with all caps to ensure that
    5.85 +        // jdeps still recognizes a multi-release jar.
    5.86 +        Attributes allCapsAttrs = new Attributes(defaultAttributes);
    5.87 +        allCapsAttrs.putValue(MRJAR_ATTR.toUpperCase(), "TRUE");
    5.88 +        build(mrjarAllCaps, allCapsAttrs);
    5.89 +    }
    5.90 +
    5.91 +    @DataProvider(name="provider")
    5.92 +    private Object[][] args() {
    5.93 +        // jdeps warning messages may be localized.
    5.94 +        // This test only checks for the English version.  Return an empty
    5.95 +        // array (skip testing) if the default language is not English.
    5.96 +        String language = Locale.getDefault().getLanguage();
    5.97 +        System.out.println("Language: " + language);
    5.98 +
    5.99 +        if ("en".equals(language)) {
   5.100 +            return new Object[][] {
   5.101 +                // one mrjar arg
   5.102 +                {   Arrays.asList(mrjar1.toString()),
   5.103 +                    Arrays.asList(mrjar1)},
   5.104 +                // two mrjar args
   5.105 +                {   Arrays.asList(mrjar1.toString(), mrjar2.toString()),
   5.106 +                    Arrays.asList(mrjar1, mrjar2)},
   5.107 +                // one mrjar arg, with mrjar on classpath
   5.108 +                {   Arrays.asList("-cp", mrjar2.toString(), mrjar1.toString()),
   5.109 +                    Arrays.asList(mrjar1, mrjar2)},
   5.110 +                // non-mrjar arg, with mrjar on classpath
   5.111 +                {   Arrays.asList("-cp", mrjar1.toString(), nonMRjar.toString()),
   5.112 +                    Arrays.asList(mrjar1)},
   5.113 +                // mrjar arg with jar attribute name/value in ALL CAPS
   5.114 +                {   Arrays.asList(mrjarAllCaps.toString()),
   5.115 +                    Arrays.asList(mrjarAllCaps)},
   5.116 +                // non-mrjar arg
   5.117 +                {   Arrays.asList(nonMRjar.toString()),
   5.118 +                    Collections.emptyList()}
   5.119 +            };
   5.120 +        } else {
   5.121 +            System.out.println("Non-English language \""+ language +
   5.122 +                    "\"; test passes superficially");
   5.123 +            return new Object[][]{};
   5.124 +        }
   5.125 +    }
   5.126 +
   5.127 +    /* Run jdeps with the arguments given in 'args', and confirm that a warning
   5.128 +     * is issued for each Multi-Release jar in 'expectedMRpaths'.
   5.129 +     */
   5.130 +    @Test(dataProvider="provider")
   5.131 +    public void checkWarning(List<String> args, List<Path> expectedMRpaths) {
   5.132 +        StringWriter sw = new StringWriter();
   5.133 +        PrintWriter pw = new PrintWriter(sw);
   5.134 +
   5.135 +        int rc = com.sun.tools.jdeps.Main.run(args.toArray(new String[args.size()]), pw);
   5.136 +        pw.close();
   5.137 +
   5.138 +        expectedMRJars(sw.toString(), expectedMRpaths);
   5.139 +        Assert.assertEquals(rc, 0, "non-zero exit code from jdeps");
   5.140 +    }
   5.141 +
   5.142 +    /* Confirm that warnings for the specified paths are in the output (or that
   5.143 +     * warnings are absent if 'paths' is empty).
   5.144 +     * Doesn't check for extra, unexpected warnings.
   5.145 +     */
   5.146 +    private static void expectedMRJars(String output, List<Path> paths) {
   5.147 +        if (paths.isEmpty()) {
   5.148 +            Assert.assertFalse(output.contains(WARNING),
   5.149 +                               "Expected no mrjars, but found:\n" + output);
   5.150 +        } else {
   5.151 +            for (Path path : paths) {
   5.152 +                String expect = "Warning: " + path.toString() + WARNING;
   5.153 +                Assert.assertTrue(output.contains(expect),
   5.154 +                        "Did not find:\n" + expect + "\nin:\n" + output + "\n");
   5.155 +            }
   5.156 +        }
   5.157 +    }
   5.158 +
   5.159 +    /* Build a jar at the expected path, containing the given attributes */
   5.160 +    private static void build(Path path, Attributes attributes) throws IOException {
   5.161 +        try (OutputStream os = Files.newOutputStream(path);
   5.162 +             JarOutputStream jos = new JarOutputStream(os)) {
   5.163 +
   5.164 +            JarEntry me = new JarEntry("META-INF/MANIFEST.MF");
   5.165 +            jos.putNextEntry(me);
   5.166 +            Manifest manifest = new Manifest();
   5.167 +            manifest.getMainAttributes().putAll(attributes);
   5.168 +            manifest.write(jos);
   5.169 +            jos.closeEntry();
   5.170 +        }
   5.171 +    }
   5.172 +}

mercurial