7

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?

Justin Garrick
  • 14,767
  • 7
  • 41
  • 66
  • 1
    From memory, I'd say the answer is no. Java still has unfixed bugs around escaping `!` in URIs (try adding that bang to the end of a directory name and then adding it to your classpath) so my gut reaction is to say that you're going to have some work to do to get it working the way you want. – ngreen Nov 30 '14 at 22:20
  • 1
    From java source code (java.net.JarURLConnection), the answer is also no: ` int separator = spec.indexOf("!/"); /* * REMIND: we don't handle nested JAR URLs */ ...` – Jonas Berlin Dec 11 '14 at 12:17

1 Answers1

1

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);
    }
}
Justin Garrick
  • 14,767
  • 7
  • 41
  • 66