|
|
|
@ -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; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
|