Closed
Description
Given the following stripped-down demo application:
@SpringBootApplication
public class InjectedPathDemoApplication implements ApplicationRunner {
@Value("${dir}")
private Path dir;
public static void main(String[] args) {
SpringApplication.run(InjectedPathDemoApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(dir);
}
}
When run using a JDK in Windows:
$ java -jar demo.jar --dir=..
..
$ java -jar demo.jar --dir=./test
test
$ java -jar demo.jar --dir=.
C:\■■■■■■■■\injected-path-demo\bin\main
When run as native binary compiled with GraalVM:
$ ./demo-native --dir=..
..
$ ./demo-native --dir=./test
test
$ ./demo-native --dir=.
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'injectedPathDemoApplication': Unsatisfied dependency expressed through field 'dir': Failed to convert value of type 'java.lang.String' to required type 'java.nio.file.Path'; Could not retrieve file for class path resource []: class path resource [] cannot be resolved to absolute file path because it does not reside in the file system: resource:/
Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'injectedPathDemoApplication': Unsatisfied dependency expressed through field 'dir': Failed to convert value of type 'java.lang.String' to required type 'java.nio.file.Path'; Could not retrieve file for class path resource []: class path resource [] cannot be resolved to absolute file path because it does not reside in the file system: resource:/
at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveValue(AutowiredFieldValueResolver.java:194)
at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveAndSet(AutowiredFieldValueResolver.java:167)
at com.example.demo.InjectedPathDemoApplication__Autowiring.apply(InjectedPathDemoApplication__Autowiring.java:17)
at org.springframework.beans.factory.support.InstanceSupplier$1.get(InstanceSupplier.java:83)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:949)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1219)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:962)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
at com.example.demo.InjectedPathDemoApplication.main(InjectedPathDemoApplication.java:17)
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.nio.file.Path'; Could not retrieve file for class path resource []: class path resource [] cannot be resolved to absolute file path because it does not reside in the file system: resource:/
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:87)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:71)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1381)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353)
at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveValue(AutowiredFieldValueResolver.java:188)
... 21 more
Caused by: java.lang.IllegalArgumentException: Could not retrieve file for class path resource []: class path resource [] cannot be resolved to absolute file path because it does not reside in the file system: resource:/
at org.springframework.beans.propertyeditors.PathEditor.setAsText(PathEditor.java:115)
at org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:439)
at org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:412)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:161)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:80)
... 25 more
Expected result for the third call: returns either "." or "", and does not throw an error on native
Metadata
Metadata
Assignees
Labels
Type
Projects
Relationships
Development
No branches or pull requests
Activity
sbrannen commentedon Jun 30, 2024
Hi @ewoerner,
Congratulations on opening your first issue for the Spring Framework! 👍
What happens if you introduce the
file:
prefix as follows?[-]Strange value injection of "." into path[/-][+]Strange `@Value` injection of "." into `Path` in native image[/+]ewoerner commentedon Jun 30, 2024
@sbrannen that causes injection to fail with any value, with the following stacktrace:
sbrannen commentedon Jun 30, 2024
How about
@Value("file://${dir}")
?ewoerner commentedon Jun 30, 2024
That also throws, but with a different root cause:
sbrannen commentedon Jun 30, 2024
Thanks for trying out both of those variants and providing feedback!
I unfortunately don't work on a Windows machine, so I don't have an easy way to test this. Though, perhaps one of my colleagues can test this on Windows.
In the interim, please let us know which versions of the following you are using.
From the stack trace, I can deduce that you're using Spring Boot 3.3.1 with Spring Framework 6.1.10.
snicoll commentedon Jul 1, 2024
There's not much Spring is doing around that call stack. Since you can easily reproduce, it would be helpful to see if the raw Java API usage throws that exception as well. Can you please replace the
@Value
injection by the following in yourrun
method?If this fails as well, we know we can close this in favour of a report in GraalVM itself.
ewoerner commentedon Jul 2, 2024
Version info, as requested:
Windows 11
OpenJDK Runtime Environment GraalVM CE 17.0.9+9.1 (build 17.0.9+9-jvmci-23.0-b22)
OpenJDK Runtime Environment Temurin-21.0.2+13 (build 21.0.2+13-LTS)
Turns out I did not test properly (I ran it from Eclipse), the exception is also reproducible without GraalVM when built as a JAR file:
So the chain seems to be as follows:
The error also happens with any other value that resolves to an existing resource, so --dir=application.properties also throws an Exception.
10 remaining items
java.nio.file.Path
(and plain "." value resolves to classpath root) #33139java.nio.file.Path
(and plain "." value resolves to classpath root) #33140jhoeller commentedon Jul 3, 2024
We're catching the
IllegalArgumentException
for non-hierarchical URIs now, letting the regular resource resolution apply which is capable of resolvingfile:.
already. Also, we're providing a more meaningful exception for our own file-resolutionIllegalArgumentException
now.Apply fallback resolution for non-hierarchical URIs such as "file:."
Apply fallback resolution for non-hierarchical URIs such as "file:."
Apply fallback resolution for non-hierarchical URIs such as "file:."