How automatically set Native Library Path and JAR's path through code - java

I was trying to automatically set the native library path and the JAR's path automatically during the runtime of a program of mine (in other words, I would like to perform the settings' definition through code.
I tried to execute the following in the beginning of my program flow:
System.setProperty("java.library.path", "\\some_folder");
apparently this should set up the native library path, but the application could not load the dlls in the folder. I've also tried some variations (like "jni.library.path") but none of them seemed to work. Is there another way to solve this?

The java.library.path is read only once when the JVM starts up. If you change this property using System.setProperty, it won't make any difference. the following blog provides options to load dlls in runtime.
http://fahdshariff.blogspot.jp/2011/08/changing-java-library-path-at-runtime.html

Related

OpenCV 4.3.0 java.lang.UnsatisfiedLinkError in Eclipse

I'm trying to do some template matching with the Java binding of OpenCV 4.3.0 in Eclipse, but attempting to load the template image always results in this error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: org.opencv.imgcodecs.Imgcodecs.imread_0(Ljava/lang/String;I)J
The line of code where this exception is thrown is this:
flowerTemplate = Imgcodecs.imread("/templates/flowerpot_white.png", Imgcodecs.IMREAD_COLOR);
I have tried a number of solutions suggested on similar questions on StackOverflow and elsewhere on the internet, including:
Pointing at the native library folder with the "Native library location" variable in the user library definition in Eclipse.
Adding the native library folder location to my PATH variable.
Adding the native library .dll location to my PATH variable.
Setting up the Eclipse run configuration to add the native library folder & .dll locations to the PATH and CLASSPATH variables.
Loading the library with the appropriate Java code, in each of the three ways I saw it suggested, in three different places which all run before the code that throws the exception.
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.load(<path_to_the_dll>);
File opencvLibrary = new File(System.mapLibraryName(Core.NATIVE_LIBRARY_NAME));
System.load(opencvLibrary.getAbsolutePath());
Placing the .dll in question into my source folder and every subfolder. I am running it from within Eclipse, so this is also the program's working directory.
UnsatisfiedLinkError is a runtime exception that happens when running your Java program. So placing your file in the source folder will not work.
You need it to be available in a place that your program can find it.
See this article for example:
https://www.javaworld.com/article/2077520/java-tip-23--write-native-methods.html
In it they place the library in Linux's library path. In windows you'd similarly place it in the current directory (where you're running from) or in some shared location.
This article explains Window's dll search order: https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
You shouldn't need to explicitly call System.loadLibrary() yourself. That's the library's responsibility.
Your problem is that OpenCV is improperly installed on your machine or inaccessible from Eclipse.
For instructions on how to make in work in Eclipse see:
Add .dll to java.library.path in Eclipse/PyDev Jython project
After removing every load method and then adding them back one-by-one, I determined that the issue was most likely caused by Eclipse loading the native library folder twice.

tomcat on ubuntu jnetpcap native library *.so unable to load [duplicate]

How can I load a custom dll file in my web application? I've tried the following:
Copied all required dlls in system32 folder and tried to load one of them in Servlet constructor System.loadLibrary
Copied required dlls into tomcat_home/shared/lib and tomcat_home/common/lib
All these dlls are in WEB-INF/lib of the web-application
In order for System.loadLibrary() to work, the library (on Windows, a DLL) must be in a directory somewhere on your PATH or on a path listed in the java.library.path system property (so you can launch Java like java -Djava.library.path=/path/to/dir).
Additionally, for loadLibrary(), you specify the base name of the library, without the .dll at the end. So, for /path/to/something.dll, you would just use System.loadLibrary("something").
You also need to look at the exact UnsatisfiedLinkError that you are getting. If it says something like:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path
then it can't find the foo library (foo.dll) in your PATH or java.library.path. If it says something like:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V
then something is wrong with the library itself in the sense that Java is not able to map a native Java function in your application to its actual native counterpart.
To start with, I would put some logging around your System.loadLibrary() call to see if that executes properly. If it throws an exception or is not in a code path that is actually executed, then you will always get the latter type of UnsatisfiedLinkError explained above.
As a sidenote, most people put their loadLibrary() calls into a static initializer block in the class with the native methods, to ensure that it is always executed exactly once:
class Foo {
static {
System.loadLibrary('foo');
}
public Foo() {
}
}
Changing 'java.library.path' variable at runtime is not enough because it is read only once by JVM. You have to reset it like:
System.setProperty("java.library.path", path);
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);
Please, take a loot at: Changing Java Library Path at Runtime.
The original answer by Adam Batkin will lead you to a solution, but if you redeploy your webapp (without restarting your web container), you should run into the following error:
java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1715)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
at java.lang.Runtime.load0(Runtime.java:787)
at java.lang.System.load(System.java:1022)
This happens because the ClassLoader that originally loaded your DLL still references this DLL. However, your webapp is now running with a new ClassLoader, and because the same JVM is running and a JVM won't allow 2 references to the same DLL, you can't reload it. Thus, your webapp can't access the existing DLL and can't load a new one. So.... you're stuck.
Tomcat's ClassLoader documentation outlines why your reloaded webapp runs in a new isolated ClassLoader and how you can work around this limitation (at a very high level).
The solution is to extend Adam Batkin's solution a little:
package awesome;
public class Foo {
static {
System.loadLibrary('foo');
}
// required to work with JDK 6 and JDK 7
public static void main(String[] args) {
}
}
Then placing a jar containing JUST this compiled class into the TOMCAT_HOME/lib folder.
Now, within your webapp, you just have to force Tomcat to reference this class, which can be done as simply as this:
Class.forName("awesome.Foo");
Now your DLL should be loaded in the common classloader, and can be referenced from your webapp even after being redeployed.
Make sense?
A working reference copy can be found on google code, static-dll-bootstrapper .
You can use System.load() to provide an absolute path which is what you want, rather than a file in the standard library folder for the respective OS.
If you want native applications that already exist, use System.loadLibrary(String filename). If you want to provide your own you're probably better with load().
You should also be able to use loadLibrary with the java.library.path set correctly. See ClassLoader.java for implementation source showing both paths being checked (OpenJDK)
In the case where the problem is that System.loadLibrary cannot find the DLL in question, one common misconception (reinforced by Java's error message) is that the system property java.library.path is the answer. If you set the system property java.library.path to the directory where your DLL is located, then System.loadLibrary will indeed find your DLL. However, if your DLL in turn depends on other DLLs, as is often the case, then java.library.path cannot help, because the loading of the dependent DLLs is managed entirely by the operating system, which knows nothing of java.library.path. Thus, it is almost always better to bypass java.library.path and simply add your DLL's directory to LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS), or Path (Windows) prior to starting the JVM.
(Note: I am using the term "DLL" in the generic sense of DLL or shared library.)
If you need to load a file that's relative to some directory where you already are (like in the current directory), here's an easy solution:
File f;
if (System.getProperty("sun.arch.data.model").equals("32")) {
// 32-bit JVM
f = new File("mylibfile32.so");
} else {
// 64-bit JVM
f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());
For those who are looking for java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path
I was facing same exception; I tried everything and important things to make it work are:
Correct version of pdf lib.jar ( In my case it was wrong version jar kept in server runtime )
Make a folder and keep the pdflib jar in it and add the folder in your PATH variable
It worked with tomcat 6.
If you believe that you added a path of native lib to %PATH%, try testing with:
System.out.println(System.getProperty("java.library.path"))
It should show you actually if your dll is on %PATH%
Restart the IDE Idea, which appeared to work for me after I setup the env variable by adding it to the %PATH%
The issue for me was naming:
The library name should begin with "lib..." such as libnative.dll.
So you might think you need to load "libnative": System.loadLibrary("libnative")
But you actually need to load "native": System.loadLibrary("native")
Poor me ! spent a whole day behind this.Writing it down here if any body replicates this issue.
I was trying to load as Adam suggested but then got caught with AMD64 vs IA 32 exception.If in any case after working as per Adam's(no doubt the best pick) walkthrough,try to have a 64 bit version of latest jre.Make sure your JRE AND JDK are 64 bit and you have correctly added it to your classpath.
My working example goes here:unstatisfied link error
I'm using Mac OS X Yosemite and Netbeans 8.02, I got the same error and the simple solution I have found is like above, this is useful when you need to include native library in the project. So do the next for Netbeans:
1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: java -Djava.library.path="your_path"
5.- for example in my case: java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok
I hope it could be useful for someone.
The link where I found the solution is here:
java.library.path – What is it and how to use
It is simple just write java -XshowSettings:properties on your command line in windows and then paste all the files in the path shown by the java.library.path.
I had the same problem and the error was due to a rename of the dll.
It could happen that the library name is also written somewhere inside the dll.
When I put back its original name I was able to load using System.loadLibrary
First, you'll want to ensure the directory to your native library is on the java.library.path. See how to do that here. Then, you can call System.loadLibrary(nativeLibraryNameWithoutExtension) - making sure to not include the file extension in the name of your library.

How to use a JNI lib, with associated libs, at an arbitrary location?

We have an app that sometimes is installed with an associated app. Both may be installed separately, at different times, and neither is usually in the OS Path environment setting.
IF both apps are installed, the one I'm working on needs to use a JNI library from the other app. This library uses a dozen or so other native libs. While I can FIND the JNI lib, I can't seem to find a way to use it without requiring the user to change their system setup.
I've found the (hacky) technique to add the JNI lib to the java.library.path, I've been unable to find any way of updating the native Path so the JNI lib can find it's associated libs.
The only things that have worked so far are to:
Add the folder that the JNI and associated files are in to the OS path before launching our app.
Launch our app so the Current Working Directory is the JNI lib folder.
Neither of which makes for a hassle-free user experience.
So, is there any way for a Java app to modify it's own environment Path so the JNI lib can find it's associated native libs? (currently testing on Win7, will also need to support OS/X)
This can not be done with an unknown location at run time. According to jni documentation
"To load your shared native library module in Java, simply use Java's System.loadLibrary method in a Java class:"
as well as
"Another common reason for the native library not loading is because it is not in your path. On Windows make sure the path environment variable contains the path to the native library. On Unix make sure that your LD_LIBRARY_PATH contains the path to the native library. Adding paths to LD_LIBRARY_PATH can slow down other programs on your system so you may want to consider alternative approaches. For example you could recompile your native library with extra path information using -rpath if you're using GNU, see the GNU linker documentation (ld man page). You could use a command such as ldconfig (Linux) or crle (Solaris) to add additional search paths to the default system configuration (this requires root access and you will need to read the man pages)."
So thus you need to know the location and must be in a path to be able to load the file. If the location is not known it can not be done due to how jni works and the jvm works.
One way to load a JNI lib with dependent libraries is to load each of the dependents then load the JNI library.
For example, if bar.so is dependent on foo.so and both libraries exist in /some/dir, do the following:
System.load("/some/dir/foo.so");
System.load("/some/dir/bar.so");
Use System.load() instead of System.loadLibrary() so you can specify the absolute path to the library.
You'll have to load all dependents of all loaded libraries unless they can be found in the java.library.path path.
Hope this helps.

UnsatisfiedLinkError, but library is in path

I'm a little confused by this error. I'm new to Java and the error seems pretty self explanatory, but I've checked my paths (even defined my own) and it still fails to find this library. Is there something I'm doing wrong? See directory screenshot and error screenshot below:
UPDATE
UPDATE 2
If I create a new NetBeans project this works fine. Same code and everything. If I create new IntelliJ project I get this error above. I must be missing something in IntelliJ
UPDATE 3
Found the solution. Adding dependencies is a bit different in IntelliJ. Thanks all for the help.
http://www.jetbrains.com/idea/webhelp/configuring-module-dependencies-and-libraries.html
Obidisc4j is a .jar file. You just dont see its extension in the explorer.
Regular jar files are not loaded by System.loadLibrary. They are automatically loaded by the JVM's classLoader.
You are using a native library. It doen't matter if that library is in the classpath. There are 4 ways you can make the Java runtime load your shared library at runtime:
Call System.load to load the .so from an explicitly specified absolute path.
Copy the shared library to one of the paths already listed in java.library.path
Modify the LD_LIBRARY_PATH environment variable to include the directory where the shared library is located.
Specify the java.library.path on the command line by using the -D option.
Seems like your application is trying to find out a obidisc4j.dll (for Windows) or obidisc4j.so (for Linux). The file must be present on the PATH (but not the classpath). If you are not sure what PATH is your Java application searching in, you can write the following statement, before the point where the exception takes place, to find out the PATH.
System.out.println(System.getProperty("java.library.path"));
This will tell you about the paths where your DLL or SO file should be placed. You just need to place the file in ONE of those N-paths.

sigar-amd64-winnt.dll ... can't reference it or bundle it with .jar

(It might be an obvious mistake I'm making, but I couldn't get it to work after 6 hours now.)
I'm trying to get CPU information using the sigar.jar in my eclipse project (just testing the sigar API for now).
It runs in eclipse without problems:
what made it work in eclipse was to put the dll in the same folder as
the sigar.jar
I tested that adding a path to the dll as the "native code property"
in the build path config dialog has no effect.
Adding vm arguments in the run configuration also has no effect.
I tested putting 2 fake paths in those 2 places and as long as I have the
dll in the same folder as the sigar.jar... it runs well in eclipse.
The problem is when I try to export a runnable .jar file for my project. I tried 2 things:
I modified the MANIFEST.MF file with Bundle-NativeCode: libs/sigar-amd64-winnt.dll (I'm assuming here the path is relative to the project folder) --> no success:
main starting!! no sigar-amd64-winnt.dll in java.library.path
org.hyperic.sigar.SigarException: no sigar-amd64-winnt.dll in
java.library.path
at org.hyperic.sigar.Sigar.loadLibrary(Sigar.java:172)
at org.hyperic.sigar.Sigar.<clinit>(Sigar.java:100)
at CpuData.main(CpuData.java:59)
cpudata(sigar s) starting!!! cpuInfo() starting!!!
Exception in thread
"main" java.lang.UnsatisfiedLinkError:
org.hyperic.sigar.Sigar.getCpuInfoList()[Lorg/hyperic/sigar/C puInfo;
at org.hyperic.sigar.Sigar.getCpuInfoList(Native Method)
at CpuData.cpuInfo(CpuData.java:103)
at CpuData.<init>(CpuData.java:29)
at CpuData.main(CpuData.java:59)
Then I decided to put the .dll in the same folder as my project.jar, and used in the command line: java -Djava.library.path=./native/ -jar C:\cpu_usage_log\cpu3.jar (I'm assuming here the path is relative to the folder that contains the project.jar) ...but again no success:
Error: impossible to find or load the main class .library.path=..native
(I suspected that I should give a main class name as a second argument after the -Djava.library.path=./path/ but I can't find that supposed "main class" name, or any examples on the web that do specify such a class ...is it a main class from within the .dll?)
I don't really know what else to try at this point. I read those 2 solutions worked for others, and it makes it even more frustrating because I imagine it could something obvious that I missed or didn't understand when reading other posts and that I just can't find (it's the first time I deal with native dlls in a java project).
For me it was always the best to modify the way how Java loads the library.
Usually you call System.loadLibrary("mylib"); which searches the library on the library path.
IMHO it is much better loading the library using it's absolute path. This allows you to implement a custom search logic in your program:
// Extends the name to mylib.so or mylib.dll
mylibname = System.mapLibraryName("mylib");
// Load the library via its absolute path
System.load(new File(path, mylibname).getAbsolutePath());
Note that each library can only be loaded once, therefore if you load the library as shown above, calls of System.loadLibrary("mylib"); afterwards will be ignored as the library is already loaded.

Categories