Path -> URI -> Path round trip fails for lazily created zip file systems

Philippe Marschall philippe.marschall at gmail.com
Wed Dec 25 07:23:32 PST 2013


Hi

When you create a ZIP file system on a zip file that doesn’t exist
(option ”create" set to "false”) then the following will fail

Paths.get(path.toUri())

This issue is that in this case the file system is stored under a null
key in ZipFileSystemProvider#filesystems instead of the real path
(this may break other things as well). It seems to be caused by the
following code in ZipFileSystemProvider.newFileSystem(URI, Map<String,
?>)

    public FileSystem newFileSystem(URI uri, Map<String, ?> env)
        throws IOException
    {
        Path path = uriToPath(uri);
        synchronized(filesystems) {
            Path realPath = null;
            if (ensureFile(path)) {
                realPath = path.toRealPath();
                if (filesystems.containsKey(realPath))
                    throw new FileSystemAlreadyExistsException();
            }
            ZipFileSystem zipfs = null;
            try {
                zipfs = new ZipFileSystem(this, path, env);
            } catch (ZipError ze) {
                String pname = path.toString();
                if (pname.endsWith(".zip") || pname.endsWith(".jar"))
                    throw ze;
                // assume NOT a zip/jar file
                throw new UnsupportedOperationException();
            }
            filesystems.put(realPath, zipfs);
            return zipfs;
        }
    }

The problem is that when “path” does not exist then #ensureFile will
return false. In this case realPath will remain null. I don’t know why
this check is done there so I’m not sure what the fix is.

A simple test case for this is


  @Test
  public void jarToUriRegression() throws IOException {
    Path jarFolder = Files.createTempDirectory("jartest");
    try {
      Path jarFile = jarFolder.resolve("test.jar");
      try {
        Map<String, String> env = Collections.singletonMap("create", "true");
        URI uri = URI.create("jar:" + jarFile.toUri());
        try (FileSystem jarfs = FileSystems.newFileSystem(uri, env)) {
          Path p = jarfs.getPath("hello.txt");
          assertNotNull(Paths.get(p.toUri()));
        }
      } finally {
        Files.delete(jarFile);
      }
    } finally {
      Files.delete(jarFolder);
    }
  }

I tested with the latest b121 of JDK8.

Cheers
Philippe


More information about the nio-dev mailing list