I am trying to create an executable jar file for a project which has a java library resource folder as dependency within the project itself. I want to deploy that jar without the need for the user to download that dependency separately. So I added that java library as a resource to my project and built it. Inside the project source-code, I have the following code to try and set "java.library.path" to include that resource.
Here is what my code looks like:
URL url = Staple.class.getResource("/path/to/java_library_name");
String stringUrl = url.toString();
System.setProperty( "java.library.path", stringUrl );
Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null );
However, when building the code and trying to execute the jar itself, this doesn't work and I am getting the following error:
no java_library_name in java.library.path: [jar, file, /path/to/project/target/jar_name-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/path/to/java_library_name]
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2660)
at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:829)
at java.base/java.lang.System.loadLibrary(System.java:1867)
.....
What is the problem with the above code? It looks like it got the whole path wrong and composed something like /path/to/project/target/jar_name-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/path/to/java_library_name
How otherwise can I programmatically retrieve the path which includes the java library folder after jar is created, and during runtime?
native resources (the ones you are trying to load with loadLibrary) need to be FILES, and the resources returned by
MyClass.class.getResourceare URLs; on purpose, as they need not be files. In fact, they usually aren't, as is the case right here: Your resource isn't a file. It's a zip entry in a jar file, which is not a file.There's no way around this; OS restriction.
I know, I know. Sucks. But you gotta do it: Unpack the DLL into a temporary location (you CAN do this; use
getResourceAsStreaminstead, and copy it to a file using the newFilesAPI; it's a one-liner these days (Files.write), then load that.Of course, writing executable code into a temp dir and then executing it is very security sensitive; I have no solutions for that dilemma.