Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a FileSystem to a jar inside another jar

Tags:

java

nio

I am trying to use NIO FileSystem to access a jar inside another jar. Call the outside jar my-outer.jar and the inner my-inner.jar (Using Java 8 and Windows 7 but I think that is not the issue)

I am using the following code

    String zipfilePath = "c:/testfs/my-outer.jar!/my-inner.jar";
    Path path = Paths.get(zipfilePath);
    try(ZipFileSystem zipfs = (ZipFileSystem) FileSystems.newFileSystem(path, null))
    { ...  }

but I am getting the exception below when trying to create that newFileSystem:

Exception in thread "main" java.nio.file.FileSystemNotFoundException: C:\testfs\my-outer.jar!\my-inner.jar

Note that if I just use the outer jar as the FileSystem, that works perfectly fine and I can read and write files from it beautifully. It's just when I try to reach into the inner archive that the troubles begin.

Doesn't FileSystem support the JarURLConnection notation?

like image 637
Victor Grazi Avatar asked Apr 17 '15 19:04

Victor Grazi


People also ask

Can a JAR file contain a JAR file?

A JAR file is actually just a ZIP file. It can contain anything - usually it contains compiled Java code (*.

Can a JAR file be modified?

You can use the JAR file editor to view or edit JAR file information that is stored in a data development project. If you make changes to JAR file information using the editor, you must deploy the JAR file to the database server again to apply the changes to the server version of the JAR file.


1 Answers

As said by vbezhenear and as experimented by myself the JarURLConnection notation in the form c:/testfs/my-outer.jar!/my-inner.jar seems not implemented by the factory method FileSystems.newFileSystem(Path path, ClassLoader loader).

But you can still access the inner jar like this:

Path outerPath = Paths.get("c:/testfs/my-outer.jar");
try (FileSystem outerFS = FileSystems.newFileSystem(outerPath, null)) {
    Path innerPath = outerFS.getPath("/my-inner.jar");
    try (FileSystem innerFS = FileSystems.newFileSystem(innerPath, null)) {
       ...
    }
}

--UPDATE--

If you try to use an URI instead of a Path you can create a ZipFileSystem like this

URI uri = URI.create("jar:file:/home/orto/stackoverflow/outer.jar!/inner.jar");
Map<String,String> env = Collections.emptyMap();
try(ZipFileSystem zipfs = (ZipFileSystem)FileSystems.newFileSystem(uri,env))
{...}

But no luck you get access to the outer.jar and not the inner.jar

If you look at the source code of JarFileSystemProvider you see

@Override
protected Path uriToPath(URI uri) {
    String scheme = uri.getScheme();
    if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
        throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
    }
    try {
        String uristr = uri.toString();
        int end = uristr.indexOf("!/");
        uristr = uristr.substring(4, (end == -1) ? uristr.length() : end);
        uri = new URI(uristr);
        return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null))
                    .toAbsolutePath();
    } catch (URISyntaxException e) {
        throw new AssertionError(e); //never thrown
    }
}

The path is cut up before the first "!". So there is no way to directly create a file system on the inside jar from the newFileSystem method.

like image 112
Ortomala Lokni Avatar answered Sep 23 '22 20:09

Ortomala Lokni