Search code examples
javajarjava-8

get FileSystems of a jar inside another jar


This is what I'm trying to do:

FileSystem fs1 = FileSystems.newFileSystem(Paths.get("f1.jar"), null);
FileSystem fs2 = FileSystems.newFileSystem(fs1.getPath("/f2.jar"), null);

but I get a java.nio.file.ProviderNotFoundException thrown by FileSystems.newFileSystem() on the second line.

What am I doing wrong?

Thanks!


Solution

  • You have to extract nested jar first.

    Edit: Answers on oracle forum don't give clear reason why you have to extract jar first.

    Here is quote from Rajendra Gutupalli's blog (author of com.sun.nio.zipfs):

    Let's assume that we have a Jar file nested inside a Zip. The following program prints the contents of the MANIFEST.MF file which is inside nested jarCompress1.jar file.

    import java.io.BufferedInputStream; 
    import java.nio.file.*; 
    import java.util.HashMap; 
    import java.util.Map;
    
    public class ReadEntry {
    
        public static void main(String... args) throws Exception {
            Path zipfile = Path.get("c:/zips/zip1.zip");
            Map<String, String> env = new HashMap();
            FileSystem manager = FileSystems.newFileSystem(zipfile, env,null);
            Path path = manager.getPath("/jarCompress1.jar/META-INF/MANIFEST.MF");
            System.out.println("Reading input stream");
            BufferedInputStream bis = new BufferedInputStream(path.newInputStream());
            int ch = -1;
            while ((ch = bis.read()) != -1) {
                System.out.print((char) ch);
            }
        } 
    }
    

    And another one:

    Important point to note here is, zip file path can expand to nested zips or jars in the file's path name. For example, /home/userA/zipfile.zip/DirA/dirB/jarFile.jar/META-INF/MANIFEST.MF accesses the jar file “jarFile.jar” inside Zip file “/home/userA/zipfile.zip”.

    I couldn't reproduce claimed behavior. Next code:

    try (FileSystem fs1 = FileSystems.newFileSystem(Paths.get("f1.zip"), null)) {
        Path path = fs1.getPath("/f2.zip/test.txt");
        Files.lines(path).forEach(System.out::println);
    }
    

    Gives exception

    Exception in thread "main" java.nio.file.NoSuchFileException: f2.zip/test.txt
      at com.sun.nio.zipfs.ZipFileSystem.newInputStream(ZipFileSystem.java:544)
      at com.sun.nio.zipfs.ZipPath.newInputStream(ZipPath.java:645)
      at com.sun.nio.zipfs.ZipFileSystemProvider.newInputStream(ZipFileSystemProvider.java:278)
      at java.nio.file.Files.newInputStream(Files.java:152)
      at java.nio.file.Files.newBufferedReader(Files.java:2781)
      at java.nio.file.Files.lines(Files.java:3741)
      at java.nio.file.Files.lines(Files.java:3782)
    

    May be someone would confirm that it's a bug or point to the error in my code.

    Meanwhile returning to your original question. You cannot create FileSystem inside zip(jar) because there is no FileSystemProvider (look source code of newFileSystem method) which can create FileSystem instance from ZipPath. Hence you have to options extract the from outer zip or write your own FileSystemProvider implementation.