Browse Source

Restore GraalVM native image resource scanning support

This commit restores support for the GraalVM native image file system
in PathMatchingResourcePatternResolver.

Closes gh-29226
pull/29282/head
Sam Brannen 4 years ago
parent
commit
df58c00bf5
  1. 118
      spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java

118
spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java

@ -31,11 +31,15 @@ import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -736,6 +740,19 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
URI rootDirUri; URI rootDirUri;
try { try {
rootDirUri = rootDirResource.getURI(); rootDirUri = rootDirResource.getURI();
// If the URI is for a "resource" in the GraalVM native image file system, we have to
// ensure that the root directory does not end in a slash while simultaneously ensuring
// that the root directory is not an empty string (since Path#resolve throws an
// ArrayIndexOutOfBoundsException in a native image if the initial Path is created
// from an empty string).
String scheme = rootDirUri.getScheme();
String path = rootDirUri.getPath();
if ("resource".equals(scheme) && (path.length() > 1) && path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
// Retain the fragment as well, since root folders in the native image
// file system are indexed via the fragment (e.g., resource:/#1).
rootDirUri = new URI(scheme, path, rootDirUri.getFragment());
}
} }
catch (Exception ex) { catch (Exception ex) {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
@ -744,60 +761,75 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
return Collections.emptySet(); return Collections.emptySet();
} }
Path rootPath = null; FileSystem fileSystem = null;
if (rootDirUri.isAbsolute() && !rootDirUri.isOpaque()) { try {
// Prefer Path resolution from URI if possible Path rootPath = null;
try { if (rootDirUri.isAbsolute() && !rootDirUri.isOpaque()) {
rootPath = Path.of(rootDirUri); // Prefer Path resolution from URI if possible
} try {
catch (Exception ex) { try {
if (logger.isDebugEnabled()) { rootPath = Path.of(rootDirUri);
logger.debug("Failed to resolve %s in file system: %s".formatted(rootDirUri, ex)); }
catch (FileSystemNotFoundException ex) {
// If the file system was not found, assume it's a custom file system that needs to be installed.
fileSystem = FileSystems.newFileSystem(rootDirUri, Map.of(), ClassUtils.getDefaultClassLoader());
rootPath = Path.of(rootDirUri);
}
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to resolve %s in file system: %s".formatted(rootDirUri, ex));
}
// Fallback via Resource.getFile() below
} }
// Fallback via Resource.getFile() below
} }
} if (rootPath == null) {
if (rootPath == null) { // Resource.getFile() resolution as a fallback -
// Resource.getFile() resolution as a fallback - // for custom URI formats and custom Resource implementations
// for custom URI formats and custom Resource implementations rootPath = Path.of(rootDirResource.getFile().getAbsolutePath());
rootPath = Path.of(rootDirResource.getFile().getAbsolutePath()); }
}
String rootDir = StringUtils.cleanPath(rootPath.toString()); String rootDir = StringUtils.cleanPath(rootPath.toString());
if (!rootDir.endsWith("/")) { if (!rootDir.endsWith("/")) {
rootDir += "/"; rootDir += "/";
} }
String resourcePattern = rootDir + StringUtils.cleanPath(subPattern); String resourcePattern = rootDir + StringUtils.cleanPath(subPattern);
Predicate<Path> isMatchingFile = (path -> Files.isRegularFile(path) && Predicate<Path> isMatchingFile = path -> (Files.isRegularFile(path) &&
getPathMatcher().match(resourcePattern, StringUtils.cleanPath(path.toString()))); getPathMatcher().match(resourcePattern, StringUtils.cleanPath(path.toString())));
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Searching directory [%s] for files matching pattern [%s]" logger.trace("Searching directory [%s] for files matching pattern [%s]"
.formatted(rootPath.toAbsolutePath(), subPattern)); .formatted(rootPath.toAbsolutePath(), subPattern));
} }
Set<Resource> result = new LinkedHashSet<>(); Set<Resource> result = new LinkedHashSet<>();
try (Stream<Path> files = Files.walk(rootPath)) { try (Stream<Path> files = Files.walk(rootPath)) {
files.filter(isMatchingFile).sorted().forEach(file -> { files.filter(isMatchingFile).sorted().forEach(file -> {
try { try {
result.add(new FileSystemResource(file)); result.add(new FileSystemResource(file));
} }
catch (Exception ex) { catch (Exception ex) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Failed to convert file %s to an org.springframework.core.io.Resource: %s" logger.debug("Failed to convert file %s to an org.springframework.core.io.Resource: %s"
.formatted(file, ex)); .formatted(file, ex));
}
} }
});
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to complete search in directory [%s] for files matching pattern [%s]: %s"
.formatted(rootPath.toAbsolutePath(), subPattern, ex));
} }
}); }
return result;
} }
catch (Exception ex) { finally {
if (logger.isDebugEnabled()) { if (fileSystem != null) {
logger.debug("Failed to complete search in directory [%s] for files matching pattern [%s]: %s" fileSystem.close();
.formatted(rootPath.toAbsolutePath(), subPattern, ex));
} }
} }
return result;
} }
/** /**

Loading…
Cancel
Save