In a Java project, I am using a third-party library that loads some native library via
System.loadLibrary("libName");
I’d like to be able to influence the search path of this method from within my application, so that the user doesn’t need to specify a correct java.library.path value on the command line (this value depends on the current OS and architecture). E.g on Windows I want to set it to “lib/native/windows”, on Linux 32bit to “lib/native/linux32” etc.
I tried
System.setProperty("java.library.path", ...)
but this is ignored, apparently because the JVM reads this property only once before my code is run.
I also tried to load the native libray before using the Java library that depends on it with
System.load("fullPath/lib")
This call succeeds, but there will still be an UnsatisfiedLinkError when the native library is loaded again with System.loadLibrary().
The only way I found is the following:
- Add interfaces that abstract the whole API of the external library.
- Use only these interfaces in the rest of the code.
- Add classes that implement the interfaces and delegate to the library.
- Write an own ClassLoader, that
- overwrites findLibary() so that the native library is found in the correct path
- overwrites loadClass() and loads all classes of the external library and the wrapper layer by itself instead of trying to delegate to its parent like the default ClassLoader would do
- Ensure that the interfaces are loaded with the normal ClassLoader and the wrapping classes and the external library are loaded with my own ClassLoader.
This works, but I find it very complicated and it is much effort because I need to add all those interfaces. Is there a simpler way?
Advertisement
Answer
- There is no approved way to change the library path for a running JVM.
- You cannot load a native library more than once … and you cannot unload a native library so that you can load it again: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4171986
Based on your comments above (particularly, the behavior of the 3rd-party library), I’d say that your best option is to get the library path right when you launch the JVM.
Note that there is a hacky way to change the library path (see https://stackoverflow.com/a/24258955/139985) but it involves nasty reflection, and it reportedly doesn’t work for all Java releases. Certainly, it relies on undocumented private implementation details of ClassLoader
that could change from one release to the next.