Skip to content

Commit

Permalink
Support multiple nesting of JAR files
Browse files Browse the repository at this point in the history
* Make sure that `jar:file:///...` are properly formed (the sub-URL must have a scheme of `file`)
* When there is no `!` in the JAR URL, treat the file as a JAR and process its root path
* Otherwise recursively resolve each segment which is `!`-terminated
  • Loading branch information
dmlloyd committed Mar 25, 2024
1 parent 853804c commit fc407ab
Showing 1 changed file with 29 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,25 @@ public static <R> R processAsPath(URL url, Function<Path, R> function) {
}

final String file = url.getFile();
final int exclam = file.lastIndexOf('!');
final Path jar;
final int exclam = file.indexOf('!');
try {
jar = toLocalPath(exclam >= 0 ? new URL(file.substring(0, exclam)) : url);
URL fileUrl;
String subPath;
if (exclam == -1) {
// assume the first element is a JAR file, not a plain file, since it was a `jar:` URL
fileUrl = new URL(file);
subPath = "/";
} else {
fileUrl = new URL(file.substring(0, exclam));
subPath = file.substring(exclam + 1);
}
if (!fileUrl.getProtocol().equals("file")) {
throw new IllegalArgumentException("Sub-URL of JAR URL is expected to have a scheme of `file`");
}
return processAsJarPath(toLocalPath(fileUrl), subPath, function);
} catch (MalformedURLException e) {
throw new RuntimeException("Failed to create a URL for '" + file.substring(0, exclam) + "'", e);
}
try (FileSystem jarFs = FileSystems.newFileSystem(jar, (ClassLoader) null)) {
Path localPath = jarFs.getPath("/");
if (exclam >= 0) {
localPath = localPath.resolve(file.substring(exclam + 1));
}
return function.apply(localPath);
} catch (IOException e) {
throw new UncheckedIOException("Failed to read " + jar, e);
}
}

if (FILE.equals(url.getProtocol())) {
Expand All @@ -154,6 +157,20 @@ public static <R> R processAsPath(URL url, Function<Path, R> function) {
throw new IllegalArgumentException("Unexpected protocol " + url.getProtocol() + " for URL " + url);
}

private static <R> R processAsJarPath(Path jarPath, String path, Function<Path, R> function) {
try (FileSystem jarFs = FileSystems.newFileSystem(jarPath, (ClassLoader) null)) {
Path localPath = jarFs.getPath("/");
int idx = path.indexOf('!');
if (idx == -1) {
return function.apply(localPath.resolve(path));
} else {
return processAsJarPath(localPath.resolve(path.substring(0, idx)), path.substring(idx + 1), function);
}
} catch (IOException e) {
throw new UncheckedIOException("Failed to read " + jarPath, e);
}
}

/**
* Invokes a consumer providing the input streams to read the content of the URL.
* The consumer does not have to close the provided input stream.
Expand Down

0 comments on commit fc407ab

Please sign in to comment.