Search code examples
javajaruriarchivenio2

Do valid java.net.URIs for nested archives exist?


It's possible, although perhaps ill-advised, to read archive formats that are basically renamed .zip files (.ear, .war, .jar, etc.), by using the jar: URI scheme.

For example, the following code works well when the uri variable evaluates to a single, top-level archive, e.g. when uri equals jar:file:///Users/justingarrick/Desktop/test/my_war.war!/

private FileSystem createZipFileSystem(Path path) throws IOException {
    URI uri = URI.create("jar:" + path.toUri().toString());
    FileSystem fs;

    try {
        fs = FileSystems.getFileSystem(uri);
    } catch (FileSystemNotFoundException e) {
        fs = FileSystems.newFileSystem(uri, new HashMap<>());
    }

    return fs;
}

However, the getFileSystem and newFileSystem calls fail with an IllegalArgumentException when the URI contains nested archives, e.g. when uri equals jar:jar:file:///Users/justingarrick/Desktop/test/my_war.war!/some_jar.jar!/ (a .jar inside of a .war).

Is there a valid java.net.URI scheme for nested archive files?


Solution

  • As stated in Jonas Berlin's comment above, the answer is no. From the java.net.JarURLConnection source:

    /* get the specs for a given url out of the cache, and compute and
     * cache them if they're not there.
     */
    private void parseSpecs(URL url) throws MalformedURLException {
        String spec = url.getFile();
    
        int separator = spec.indexOf("!/");
        /*
         * REMIND: we don't handle nested JAR URLs
         */
        if (separator == -1) {
            throw new MalformedURLException("no !/ found in url spec:" + spec);
        }
    
        jarFileURL = new URL(spec.substring(0, separator++));
        entryName = null;
    
        /* if ! is the last letter of the innerURL, entryName is null */
        if (++separator != spec.length()) {
            entryName = spec.substring(separator, spec.length());
            entryName = ParseUtil.decode (entryName);
        }
    }