Avoid enumerating every jar entry in FileUtil::listResourceDirectory

Use 'java.nio.file.FileSystem' in place of 'java.util.jar.JarFile' to
list all the resources under a given classpath (on Windows & Linux), as
that is a bit neater and potentially more efficient than scanning the
entire ZIP directory structure.
This commit is contained in:
Steven Barclay 2021-12-07 13:21:01 +00:00 committed by Christoph Atteneder
parent e07c7b5d4b
commit 34409638f7
No known key found for this signature in database
GPG key ID: CD5DC1C529CDFD3B

View file

@ -24,11 +24,12 @@ import com.google.common.io.Files;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -37,14 +38,13 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
@ -177,38 +177,31 @@ public class FileUtil {
}
}
// adapted from https://stackoverflow.com/questions/3923129/get-a-list-of-resources-from-classpath-directory/48190582#48190582
public static List<String> listResourceDirectory(String directoryName) throws IOException, ResourceNotFoundException {
URL url = Thread.currentThread().getContextClassLoader().getResource(directoryName);
if (url == null) {
throw new ResourceNotFoundException(directoryName);
}
URI uri;
try {
uri = url.toURI();
} catch (URISyntaxException e) {
throw new IOException(e);
}
if (url.getProtocol().equals("file")) {
try {
File dir = new File(url.toURI());
String[] filenames = dir.list();
if (filenames != null) {
return List.of(filenames);
}
} catch (URISyntaxException e) {
throw new IOException(e);
File dir = new File(uri);
String[] filenames = dir.list();
if (filenames != null) {
return List.of(filenames);
}
} else if (url.getProtocol().equals("jar")) {
List<String> filenames = new ArrayList<>();
String dirname = directoryName + "/";
String path = url.getPath();
String jarPath = path.substring(5, path.indexOf("!"));
try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) {
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
if (name.startsWith(dirname) && !dirname.equals(name)) {
filenames.add(name.substring(dirname.length()));
}
}
try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
Stream<Path> filePaths = java.nio.file.Files.walk(fileSystem.getPath(directoryName), 1)) { //NOPMD
return filePaths
.skip(1)
.map(path -> path.getFileName().toString())
.collect(Collectors.toUnmodifiableList());
}
return filenames;
}
throw new IOException("Failed to list resource directory: " + directoryName);
}