8153391: an image created for \"jdk.compiler\" fails to run javac
authorjlahoda
Mon, 22 Aug 2016 09:59:43 +0200
changeset 40513 39b67170b045
parent 40512 b9359154240c
child 40514 fa42e8040550
8153391: an image created for \"jdk.compiler\" fails to run javac Summary: Improving errors produced by javac when the zipfs implementation is missing in the JDK image. Reviewed-by: jjg
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/test/tools/javac/diags/examples.not-yet.txt
langtools/test/tools/javac/file/LimitedImage.java
langtools/test/tools/javac/modules/InheritRuntimeEnvironmentTest.java
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java	Fri Aug 19 13:55:26 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java	Mon Aug 22 09:59:43 2016 +0200
@@ -29,7 +29,7 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
+import java.nio.file.spi.FileSystemProvider;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -118,4 +118,19 @@
             return list;
         }
     }
+
+    private FileSystemProvider jarFSProvider;
+
+    public synchronized FileSystemProvider getJarFSProvider() {
+        if (jarFSProvider != null) {
+            return jarFSProvider;
+        }
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            if (provider.getScheme().equals("jar")) {
+                return (jarFSProvider = provider);
+            }
+        }
+        return null;
+    }
+
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Fri Aug 19 13:55:26 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Mon Aug 22 09:59:43 2016 +0200
@@ -69,6 +69,7 @@
 
 import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
 import com.sun.tools.javac.file.RelativePath.RelativeFile;
+import com.sun.tools.javac.util.Assert;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -509,7 +510,9 @@
             this.archivePath = archivePath;
             if (multiReleaseValue != null && archivePath.toString().endsWith(".jar")) {
                 Map<String,String> env = Collections.singletonMap("multi-release", multiReleaseValue);
-                this.fileSystem = getJarFSProvider().newFileSystem(archivePath, env);
+                FileSystemProvider jarFSProvider = fsInfo.getJarFSProvider();
+                Assert.checkNonNull(jarFSProvider, "should have been caught before!");
+                this.fileSystem = jarFSProvider.newFileSystem(archivePath, env);
             } else {
                 this.fileSystem = FileSystems.newFileSystem(archivePath, null);
             }
@@ -597,20 +600,6 @@
         }
     }
 
-    private FileSystemProvider jarFSProvider;
-
-    private FileSystemProvider getJarFSProvider() throws IOException {
-        if (jarFSProvider != null) {
-            return jarFSProvider;
-        }
-        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
-            if (provider.getScheme().equals("jar")) {
-                return (jarFSProvider = provider);
-            }
-        }
-        throw new ProviderNotFoundException("no provider found for .jar files");
-    }
-
     /**
      * container is a directory, a zip file, or a non-existent path.
      */
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Fri Aug 19 13:55:26 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Mon Aug 22 09:59:43 2016 +0200
@@ -42,6 +42,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.ProviderNotFoundException;
+import java.nio.file.spi.FileSystemProvider;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -315,26 +316,30 @@
 
             if (fsInfo.isFile(file)) {
                 /* File is an ordinary file. */
-                if (!isArchive(file)
-                        && !file.getFileName().toString().endsWith(".jmod")
-                        && !file.endsWith("modules")) {
-                    /* Not a recognized extension; open it to see if
-                     it looks like a valid zip file. */
-                    try {
-                        // TODO: use of ZipFile should be updated
-                        ZipFile z = new ZipFile(file.toFile());
-                        z.close();
-                        if (warn) {
-                            log.warning(Lint.LintCategory.PATH,
-                                    "unexpected.archive.file", file);
+                if (   !file.getFileName().toString().endsWith(".jmod")
+                    && !file.endsWith("modules")) {
+                    if (!isArchive(file)) {
+                        /* Not a recognized extension; open it to see if
+                         it looks like a valid zip file. */
+                        try {
+                            FileSystems.newFileSystem(file, null).close();
+                            if (warn) {
+                                log.warning(Lint.LintCategory.PATH,
+                                        "unexpected.archive.file", file);
+                            }
+                        } catch (IOException | ProviderNotFoundException e) {
+                            // FIXME: include e.getLocalizedMessage in warning
+                            if (warn) {
+                                log.warning(Lint.LintCategory.PATH,
+                                        "invalid.archive.file", file);
+                            }
+                            return;
                         }
-                    } catch (IOException e) {
-                        // FIXME: include e.getLocalizedMessage in warning
-                        if (warn) {
-                            log.warning(Lint.LintCategory.PATH,
-                                    "invalid.archive.file", file);
+                    } else {
+                        if (fsInfo.getJarFSProvider() == null) {
+                            log.error(Errors.NoZipfsForArchive(file));
+                            return ;
                         }
-                        return;
                     }
                 }
             }
@@ -1054,6 +1059,9 @@
                     } catch (IOException e) {
                         log.error(Errors.LocnCantReadFile(p));
                         return null;
+                    } catch (ProviderNotFoundException e) {
+                        log.error(Errors.NoZipfsForArchive(p));
+                        return null;
                     }
 
                     //automatic module:
@@ -1105,13 +1113,9 @@
                                     fs.close();
                             }
                         }
-                    } catch (ProviderNotFoundException e) {
-                        // will be thrown if the file is not a valid zip file
-                        log.error(Errors.LocnCantReadFile(p));
-                        return null;
                     } catch (ModuleNameReader.BadClassFile e) {
                         log.error(Errors.LocnBadModuleInfo(p));
-                    } catch (IOException e) {
+                    } catch (IOException | ProviderNotFoundException e) {
                         log.error(Errors.LocnCantReadFile(p));
                         return null;
                     }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java	Fri Aug 19 13:55:26 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java	Mon Aug 22 09:59:43 2016 +0200
@@ -32,6 +32,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.ProviderNotFoundException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -86,7 +87,7 @@
                         }
                     }
                 }
-            } catch (IOException ex) {
+            } catch (IOException | ProviderNotFoundException ex) {
             }
         }
         SUPPORTED_JAVA_PLATFORM_VERSIONS.add(targetNumericVersion(Target.DEFAULT));
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Aug 19 13:55:26 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Aug 22 09:59:43 2016 +0200
@@ -1667,6 +1667,10 @@
 compiler.warn.unexpected.archive.file=\
     Unexpected extension for archive file: {0}
 
+# 0: path
+compiler.err.no.zipfs.for.archive=\
+    No file system provider is available to handle this file: {0}
+
 compiler.warn.div.zero=\
     division by zero
 
--- a/langtools/test/tools/javac/diags/examples.not-yet.txt	Fri Aug 19 13:55:26 2016 -0700
+++ b/langtools/test/tools/javac/diags/examples.not-yet.txt	Mon Aug 22 09:59:43 2016 +0200
@@ -102,6 +102,7 @@
 compiler.warn.unchecked.assign                          # DEAD, replaced by compiler.misc.unchecked.assign
 compiler.warn.unchecked.cast.to.type                    # DEAD, replaced by compiler.misc.unchecked.cast.to.type
 compiler.warn.unexpected.archive.file                   # Paths: zip file with unknown extn
+compiler.err.no.zipfs.for.archive                       # would need zip/jar file
 compiler.warn.unknown.enum.constant                     # in bad class file
 compiler.warn.unknown.enum.constant.reason              # in bad class file
 compiler.warn.override.equals.but.not.hashcode          # when a class overrides equals but not hashCode method from Object
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/file/LimitedImage.java	Mon Aug 22 09:59:43 2016 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/**
+ * @test
+ * @bug 8153391
+ * @summary Verify javac behaves properly in absence of zip/jar FileSystemProvider
+ * @library /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.main
+ * @run main/othervm -limitmods jdk.compiler LimitedImage
+ */
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import toolbox.JavacTask;
+import toolbox.JarTask;
+import toolbox.Task.Expect;
+import toolbox.Task.Mode;
+import toolbox.Task.OutputKind;
+import toolbox.ToolBox;
+
+public class LimitedImage {
+    public static void main(String... args) throws IOException {
+        ToolBox tb = new ToolBox();
+
+        //showing help should be OK
+        new JavacTask(tb, Mode.CMDLINE)
+                .options("--help")
+                .run().writeAll();
+
+        Path testSource = Paths.get("Test.java");
+        tb.writeFile(testSource, "class Test {}");
+
+        //when zip/jar FS is not needed, compilation should succeed
+        new JavacTask(tb, Mode.CMDLINE)
+                .classpath()
+                .files(testSource)
+                .outdir(".")
+                .run()
+                .writeAll();
+
+        Path testJar = Paths.get("test.jar").toAbsolutePath();
+
+        new JarTask(tb, testJar).run();
+
+        List<String> actualOutput;
+        List<String> expectedOutput = Arrays.asList(
+                "- compiler.err.no.zipfs.for.archive: " + testJar.toString()
+        );
+
+        //check proper diagnostics when zip/jar FS not present:
+        actualOutput = new JavacTask(tb, Mode.CMDLINE)
+                .classpath(testJar)
+                .options("-XDrawDiagnostics")
+                .files(testSource)
+                .outdir(".")
+                .run(Expect.FAIL)
+                .writeAll()
+                .getOutputLines(OutputKind.DIRECT);
+
+        if (!expectedOutput.equals(actualOutput)) {
+            throw new AssertionError("Unexpected output: " + actualOutput);
+        }
+
+        actualOutput = new JavacTask(tb, Mode.CMDLINE)
+                .sourcepath(testJar)
+                .options("-XDrawDiagnostics")
+                .files(testSource)
+                .outdir(".")
+                .run(Expect.FAIL)
+                .writeAll()
+                .getOutputLines(OutputKind.DIRECT);
+
+        if (!expectedOutput.equals(actualOutput)) {
+            throw new AssertionError("Unexpected output: " + actualOutput);
+        }
+
+        actualOutput = new JavacTask(tb, Mode.CMDLINE)
+                .options("-XDrawDiagnostics",
+                         "--module-path", testJar.toString())
+                .files(testSource)
+                .outdir(".")
+                .run(Expect.FAIL)
+                .writeAll()
+                .getOutputLines(OutputKind.DIRECT);
+
+        if (!expectedOutput.equals(actualOutput)) {
+            throw new AssertionError("Unexpected output: " + actualOutput);
+        }
+
+        expectedOutput = Arrays.asList(
+                "- compiler.err.no.zipfs.for.archive: " + testJar.toString(),
+                "1 error"
+        );
+
+        actualOutput = new JavacTask(tb, Mode.CMDLINE)
+                .classpath()
+                .options("-XDrawDiagnostics",
+                         "--module-path", testJar.getParent().toString())
+                .files(testSource)
+                .outdir(".")
+                .run(Expect.FAIL)
+                .writeAll()
+                .getOutputLines(OutputKind.DIRECT);
+
+        if (!expectedOutput.equals(actualOutput)) {
+            throw new AssertionError("Unexpected output: " + actualOutput);
+        }
+    }
+
+}
\ No newline at end of file
--- a/langtools/test/tools/javac/modules/InheritRuntimeEnvironmentTest.java	Fri Aug 19 13:55:26 2016 -0700
+++ b/langtools/test/tools/javac/modules/InheritRuntimeEnvironmentTest.java	Mon Aug 22 09:59:43 2016 +0200
@@ -128,7 +128,8 @@
         new TestCase(base)
                 .testOpts("--module-path", modules.toString(), "--limit-modules", "jdk.compiler")
                 .otherOpts("-XDrawDiagnostics",
-                        "--module-source-path", src.toString())
+                        "--module-source-path", src.toString(),
+                        "-classpath", "")
                 .files(findJavaFiles(src))
                 .expect(Task.Expect.FAIL, "compiler.err.module.not.found")
                 .run();