The DefaultResourceLoader
throws a FileNotFoundException
when an application runs in native mode and attempts to load resources from an external jar /data/app.jar
via resourceLoader.getResource("jar:file:/data/app.jar!/")
.
Stacktrace:
java.lang.IllegalStateException: Failed to execute ApplicationRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:761) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:3.0.1]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:748) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:3.0.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:3.0.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:3.0.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:3.0.1]
at de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication.main(ResourceLoaderIssueApplication.java:21) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:na]
Caused by: java.io.FileNotFoundException: class path resource [jar:file:/data/app.jar!/] cannot be resolved to URL because it does not exist
at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:226) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:6.0.3]
at de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication.run(ResourceLoaderIssueApplication.java:32) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:758) ~[de.darkatra.resourceloaderissue.ResourceLoaderIssueApplication:3.0.1]
... 5 common frames omitted
It seems like the DefaultResourceLoader
mistakenly thinks that the resource is a ClassPathResource
as, when running on the JVM, the loader correctly returns a UrlResource
.
Reproducer with details: https://github.com/DarkAtra/spring-native-resource-loader-issue
Affected Spring Boot versions: 3.0.0
, 3.0.1
Comment From: bclozel
I believe this is a known limitation of GraalVM, the "jar"
protocol is not supported at runtime in a native image with the default options. Trying to resolve a URL with a "jar"
protocol will throw an exception with the following message:
malformed URL, message:Accessing an URL protocol that was not enabled. The URL protocol jar is not tested and might not work as expected. It can be enabled by adding the --enable-url-protocols=jar option to the native-image command.
Because the exception itself is a MalformedUrlException
, we can't really tune the resource loader to report it, as it implements fallback behavior for other cases.
You can configure your application to build with the following option:
graalvmNative {
nativeBuild {
binaries {
main {
buildArgs.add('--enable-url-protocols=jar')
}
}
}
}
Or you can also choose to deal with a JarFile
instance directly:
Resource resource = this.resourceLoader.getResource("file:/data/app.jar");
try (JarFile jar = new JarFile(resource.getFile())) {
//...
}
I've added this information to the Spring Boot with GraalVM wiki page. I'm closing this issue as I don't think we can improve the situation in Spring Framework.