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; @@ -31,11 +31,15 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
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.Path;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
@ -736,6 +740,19 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol @@ -736,6 +740,19 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
URI rootDirUri;
try {
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) {
if (logger.isInfoEnabled()) {
@ -744,60 +761,75 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol @@ -744,60 +761,75 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
return Collections.emptySet();
}
Path rootPath = null;
if (rootDirUri.isAbsolute() && !rootDirUri.isOpaque()) {
// Prefer Path resolution from URI if possible
try {
rootPath = Path.of(rootDirUri);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to resolve %s in file system: %s".formatted(rootDirUri, ex));
FileSystem fileSystem = null;
try {
Path rootPath = null;
if (rootDirUri.isAbsolute() && !rootDirUri.isOpaque()) {
// Prefer Path resolution from URI if possible
try {
try {
rootPath = Path.of(rootDirUri);
}
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) {
// Resource.getFile() resolution as a fallback -
// for custom URI formats and custom Resource implementations
rootPath = Path.of(rootDirResource.getFile().getAbsolutePath());
}
if (rootPath == null) {
// Resource.getFile() resolution as a fallback -
// for custom URI formats and custom Resource implementations
rootPath = Path.of(rootDirResource.getFile().getAbsolutePath());
}
String rootDir = StringUtils.cleanPath(rootPath.toString());
if (!rootDir.endsWith("/")) {
rootDir += "/";
}
String rootDir = StringUtils.cleanPath(rootPath.toString());
if (!rootDir.endsWith("/")) {
rootDir += "/";
}
String resourcePattern = rootDir + StringUtils.cleanPath(subPattern);
Predicate<Path> isMatchingFile = (path -> Files.isRegularFile(path) &&
getPathMatcher().match(resourcePattern, StringUtils.cleanPath(path.toString())));
String resourcePattern = rootDir + StringUtils.cleanPath(subPattern);
Predicate<Path> isMatchingFile = path -> (Files.isRegularFile(path) &&
getPathMatcher().match(resourcePattern, StringUtils.cleanPath(path.toString())));
if (logger.isTraceEnabled()) {
logger.trace("Searching directory [%s] for files matching pattern [%s]"
.formatted(rootPath.toAbsolutePath(), subPattern));
}
if (logger.isTraceEnabled()) {
logger.trace("Searching directory [%s] for files matching pattern [%s]"
.formatted(rootPath.toAbsolutePath(), subPattern));
}
Set<Resource> result = new LinkedHashSet<>();
try (Stream<Path> files = Files.walk(rootPath)) {
files.filter(isMatchingFile).sorted().forEach(file -> {
try {
result.add(new FileSystemResource(file));
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert file %s to an org.springframework.core.io.Resource: %s"
.formatted(file, ex));
Set<Resource> result = new LinkedHashSet<>();
try (Stream<Path> files = Files.walk(rootPath)) {
files.filter(isMatchingFile).sorted().forEach(file -> {
try {
result.add(new FileSystemResource(file));
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert file %s to an org.springframework.core.io.Resource: %s"
.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) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to complete search in directory [%s] for files matching pattern [%s]: %s"
.formatted(rootPath.toAbsolutePath(), subPattern, ex));
finally {
if (fileSystem != null) {
fileSystem.close();
}
}
return result;
}
/**

Loading…
Cancel
Save