Do not close GraalVM Native image FileSystem after classpath scanning

As can be seen in a modified version of the following example project,
attempting to access a resource discovered via classpath scanning
within a GraalVM native image -- for example via the Files.exists(...)
invocation in FileSystemResource -- currently results in a
ClosedFileSystemException since PathMatchingResourcePatternResolver
explicitly closes the native image FileSystem that backs `resource:`
resources.

Sample project: https://github.com/joshlong/spring-boot-3-aot-graphql

To address this issue, this commit removes the explicit close()
invocation for custom FileSystems after classpath scanning in
PathMatchingResourcePatternResolver.

See https://github.com/spring-projects/spring-graphql/issues/495
Closes gh-29397
This commit is contained in:
Sam Brannen
2022-10-28 21:22:58 +02:00
parent 2ccfc7068e
commit 3c42363ba4
2 changed files with 75 additions and 65 deletions

View File

@@ -19,6 +19,7 @@ package org.springframework.core.io.support;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -129,8 +130,16 @@ class PathMatchingResourcePatternResolverTests {
List<String> actualSubPaths = getSubPathsIgnoringClassFilesEtc(pattern, pathPrefix);
// We do NOT find "support" if the pattern ENDS with a slash.
assertThat(actualSubPaths).isEmpty();
URL url = getClass().getClassLoader().getResource("org/springframework/core/io/support/EncodedResource.class");
if (!url.getProtocol().equals("jar")) {
// We do NOT find "support" if the pattern ENDS with a slash if org/springframework/core/io/support
// is in the local file system.
assertThat(actualSubPaths).isEmpty();
}
else {
// But we do find "support/" if org/springframework/core/io/support is found in a JAR on the classpath.
assertThat(actualSubPaths).containsExactly("support/");
}
}
@Test
@@ -258,6 +267,7 @@ class PathMatchingResourcePatternResolverTests {
try {
Resource[] resources = resolver.getResources(pattern);
List<String> actualNames = Arrays.stream(resources)
.peek(resource -> assertThat(resource.exists()).as(resource + " exists").isTrue())
.map(Resource::getFilename)
.sorted()
.toList();
@@ -304,7 +314,16 @@ class PathMatchingResourcePatternResolverTests {
// GraalVM native image which cannot support Path#toFile.
//
// See: https://github.com/spring-projects/spring-framework/issues/29243
return ((FileSystemResource) resource).getPath();
if (resource instanceof FileSystemResource fileSystemResource) {
return fileSystemResource.getPath();
}
try {
// Fall back to URL in case the resource came from a JAR
return resource.getURL().getPath();
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}