Closed dmlloyd closed 6 months ago
One thing I am unsure of is whether it is correct to treat URLs of form jar:file:///some/path/something.jar
as valid (current behavior) or invalid.
TestApp still fails 😭 https://github.com/magicprinc/SmallRyeConfig-SpringBoot/tree/fix2
I have put your classes inside the app and removed jar with original classes from dependencies. You can debug and see details.
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: java.lang.ExceptionInInitializerError
at fink.demo.smallryeconfigspringboot.ExampleApplication.main(ExampleApplication.java:13)
... 8 more
Caused by: java.nio.file.ProviderNotFoundException: Provider not found
at java.base/java.nio.file.FileSystems.newFileSystem(FileSystems.java:545)
at java.base/java.nio.file.FileSystems.newFileSystem(FileSystems.java:400)
at io.smallrye.common.classloader.ClassPathUtils.processAsJarPath(ClassPathUtils.java:163)
at io.smallrye.common.classloader.ClassPathUtils.processAsJarPath(ClassPathUtils.java:169)
at io.smallrye.common.classloader.ClassPathUtils.processAsPath(ClassPathUtils.java:149)
at io.smallrye.common.classloader.ClassPathUtils.consumeAsPath(ClassPathUtils.java:102)
at io.smallrye.common.classloader.ClassPathUtils.consumeAsPaths(ClassPathUtils.java:86)
at io.smallrye.config.AbstractLocationConfigSourceLoader.tryClassPath(AbstractLocationConfigSourceLoader.java:141)
at io.smallrye.config.AbstractLocationConfigSourceLoader.loadConfigSources(AbstractLocationConfigSourceLoader.java:104)
at io.smallrye.config.AbstractLocationConfigSourceLoader.loadConfigSources(AbstractLocationConfigSourceLoader.java:87)
at io.smallrye.config.PropertiesConfigSourceProvider.<init>(PropertiesConfigSourceProvider.java:37)
at fink.config.spring.SmallRyeConfigAutoConf.<clinit>(SmallRyeConfigAutoConf.java:75)
... 9 more
FAILURE: Build failed with an exception.
Do you know what URL was input into the method?
jar:file:/D:/TEMP/SmallRyeConfig-SpringBoot/build/libs/SmallRyeConfig-SpringBoot-1.0.jar!/BOOT-INF/classes!/application.properties
BTW if you simply replace lastIndexOf with indexOf - everything works (spring magic 🤷♀️)
Well, at least I was correct about it being a two-level nesting. I have an idea for a fix, but I'm going to add some additional unit tests first.
With IntelliJ IDEA you can debug jar file: you build spring jar with gradle bootJar, then you add Run/Debug configuration - JAR Application with path to your jar (e.g. D:/TEMP/SmallRyeConfig-SpringBoot/build/libs/SmallRyeConfig-SpringBoot-1.0.jar)
https://github.com/magicprinc/SmallRyeConfig-SpringBoot/tree/fixBundled
url: jar:file:/D:/TEMP/SmallRyeConfig-SpringBoot/build/libs/SmallRyeConfig-SpringBoot-1.0.jar!/BOOT-INF/classes!/application.properties
file: file:/D:/TEMP/SmallRyeConfig-SpringBoot/build/libs/SmallRyeConfig-SpringBoot-1.0.jar!/BOOT-INF/classes!/application.properties
jar: D:\TEMP\SmallRyeConfig-SpringBoot\build\libs\SmallRyeConfig-SpringBoot-1.0.jar
localPath: /BOOT-INF/classes!/application.properties
io.smallrye.common.classloader.ClassPathUtils#readStream
url: jar:file:///D:/TEMP/SmallRyeConfig-SpringBoot/build/libs/SmallRyeConfig-SpringBoot-1.0.jar!/BOOT-INF/classes!/application.properties
can be read
LOG
[main] DEBUG io.smallrye.config - SRCFG01006: Loaded ConfigSource PropertiesConfigSource[source=jar:file:///D:/TEMP/SmallRyeConfig-SpringBoot/build/libs/SmallRyeConfig-SpringBoot-1.0.jar!/BOOT-INF/classes!/application.properties] with ordinal 100
Can you determine whether the sub-entry /BOOT-INF/classes
inside of file:///D:/TEMP/SmallRyeConfig-SpringBoot/build/libs/SmallRyeConfig-SpringBoot-1.0.jar
is a JAR directory, or is it a nested JAR file? I am assuming that !
means to treat that entry as a JAR file but Spring Boot might not agree with that, but this would be an easy way to check.
Usual jar/zip directory
original/as-is dependency jars in a usual jar/zip directory
META-INF has an extra folder for itself :-)
- "dependencies":
- "BOOT-INF/lib/"
- "spring-boot-loader":
- "org/"
- "snapshot-dependencies":
- "application":
- "BOOT-INF/classes/"
- "BOOT-INF/classpath.idx"
- "BOOT-INF/layers.idx"
- "META-INF/"
OK, this version should be able to detect whether a nested entry is a JAR or a directory and act accordingly.
One more fix to prevent wrong path lookups if the !
is followed by a /
.
Works!
jarPath: D:\TEMP\SmallRyeConfig-SpringBoot\build\libs\SmallRyeConfig-SpringBoot-1.0.jar
path: /BOOT-INF/classes!/application.properties
→
localPath: /BOOT-INF/classes
path: /BOOT-INF/classes!/application.properties
The code is quite complicated, so I hope you would have enough unit tests 😅
BTW, sorry for a noob question... Why do you need such heavy machinery (FileSystems, path parsing) As far as I know Spring uses only ClassLoader.getResources, .getResourceAsStream, etc
That's a more complex question than it seems to be ;)
There are several answers though:
Path
When is it possible to have snapshot/RC version in maven repo? 😥🙏
PS: IDEA recommends flipping couple of .equals → p -> "jar".equals(p.getScheme()) → "file".equals(fileUrl.getProtocol()
I'm just doing some final testing with Quarkus to make sure nothing has broken.
Looks good.
jar:file:///...
are properly formed (the sub-URL must have a scheme offile
)!
in the JAR URL, treat the file as a JAR and process its root path!
-terminatedFixes #289