Closed LukeHornibrookHaventec closed 4 years ago
Loading any type of resource file even simple JSON files from a JAR is messy business.
I can't remember exactly, but the reason why we don't use Thread.currentThread().getContextClassLoader().getResourceAsStream()
was something to do with it working when retrieving things out of a JAR but when it came to loading things out of a regular directory it returned null. The safest way I have found was to copy the shared library to a temporary directory and load it from there.
I just tried this on my Mac and it all works when loaded from a far JAR in BUNDLED
mode. I am not sure why it's not working in a linux environment, I need to debug further.
This might be fixed because I migrated to AzureCI (#77) and identified some issues in an isolated environment. Please reopen if not fixed.
@gurpreet- I still have issue.
I've created minimal sample project here https://github.com/kakawait/lazysodium-fatjar-issue
You can simply do
mvn clean package -DskipTests
java -jar target/demo-0.0.1-SNAPSHOT.jar
to reproduce and you should see
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-2.3.4.RELEASE.jar!/:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:779) ~[spring-boot-2.3.4.RELEASE.jar!/:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) ~[spring-boot-2.3.4.RELEASE.jar!/:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.4.RELEASE.jar!/:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.4.RELEASE.jar!/:2.3.4.RELEASE]
at com.example.demo.DemoApplication.main(DemoApplication.java:14) ~[classes!/:0.0.1-SNAPSHOT]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:107) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
Caused by: co.libly.resourceloader.ResourceLoaderException: Failed to load the bundled library from resources by relative path (mac/libsodium.dylib)
at co.libly.resourceloader.SharedLibraryLoader.load(SharedLibraryLoader.java:65) ~[resource-loader-1.3.7.jar!/:na]
at com.goterl.lazycode.lazysodium.utils.LibraryLoader.loadBundledLibrary(LibraryLoader.java:133) ~[lazysodium-java-4.3.0.jar!/:na]
at com.goterl.lazycode.lazysodium.utils.LibraryLoader.loadLibrary(LibraryLoader.java:94) ~[lazysodium-java-4.3.0.jar!/:na]
at com.goterl.lazycode.lazysodium.SodiumJava.<init>(SodiumJava.java:34) ~[lazysodium-java-4.3.0.jar!/:na]
at com.goterl.lazycode.lazysodium.SodiumJava.<init>(SodiumJava.java:23) ~[lazysodium-java-4.3.0.jar!/:na]
at com.example.demo.DemoApplication$CommandLineAppStartupRunner.run(DemoApplication.java:22) ~[classes!/:0.0.1-SNAPSHOT]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795) ~[spring-boot-2.3.4.RELEASE.jar!/:2.3.4.RELEASE]
... 13 common frames omitted
Caused by: java.io.IOException: Failed to list contents of file:/tmp/demo/target/demo-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/lazysodium-java-4.3.0.jar!/mac/libsodium.dylib
at co.libly.resourceloader.ResourceLoader.doCopyDirectory(ResourceLoader.java:258) ~[resource-loader-1.3.7.jar!/:na]
at co.libly.resourceloader.ResourceLoader.copyDirectory(ResourceLoader.java:250) ~[resource-loader-1.3.7.jar!/:na]
at co.libly.resourceloader.ResourceLoader.getFileFromFileSystem(ResourceLoader.java:144) ~[resource-loader-1.3.7.jar!/:na]
at co.libly.resourceloader.ResourceLoader.copyToTempDirectory(ResourceLoader.java:89) ~[resource-loader-1.3.7.jar!/:na]
at co.libly.resourceloader.SharedLibraryLoader.load(SharedLibraryLoader.java:52) ~[resource-loader-1.3.7.jar!/:na]
... 19 common frames omitted
I think using getResourceAsStream()
as @LukeHornibrookHaventec propose could be a good alternative. And if you don't want to break existing behavior, we may introduce configuration to switch mode from (default) getResource()
to getResourceAsStream()
.
Otherwise, may you open (move to public
) method getSodiumPathInResources()
that will help using SodiumJava(String absolutePath)
constructor by letting client to manage copying native lib outside the fatjar.
Today I've to use reflection
File nativeLib = File.createTempFile("libsodium", null);
Method method = LibraryLoader.class.getDeclaredMethod("getSodiumPathInResources");
method.setAccessible(true);
String path = (String) method.invoke(null);
InputStream is = this.getClass().getClassloader().getResourceAsStream(path);
Files.copy(is, nativeLib.toPath(), StandardCopyOption.REPLACE_EXISTING);
LazySodiumJava lazySodiumJava = new LazySodiumJava(new SodiumJava(nativeLib.getAbsolutePath()));
I'm not able to re-open, may I've to re-create the issue?
I'm encountering an error loading the bundled libsodium library using lazysodium 4.2.6 (and resource-loader 1.3.7) deployed within a fat jar. Here is a partially redacted stack trace:
After testing locally,
ResourceLoader.getThisJarPath()
returns a value such asjar:file:/opt/<path to the fat jar>.jar!/BOOT-INF/lib/lazysodium-java-4.2.6.jar!/
. This in turn leads to aNoSuchFileException
when loading theJarFile
inResourceLoader.isJarFile()
.As an alternative approach to manually processing the jar file, can we instead use
Thread.currentThread().getContextClassLoader().getResourceAsStream()
to read the bundled libsodium` resource directly?