添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
调皮的番茄  ·  野狐岭之战_百度百科·  5 月前    · 
单身的斑马  ·  页面重载开启·  1 年前    · 

Introduction: Using Native Libraries in Java

A native library is a library containing code compiled for a specific (native) architecture. There are certain scenarios like hardware-software integrations and process optimizations where using libraries written for different platforms can be very useful or even necessary. For this purpose, Java provides the Java Native Interface (JNI), which allows Java code that runs inside a Java Virtual Machine (JVM) to interoperate with applications and libraries written in other programming languages, such as C, C++, and assembly. The JNI enables Java code to call and be called by native applications and libraries written in other languages and it enables programmers to write native methods to handle situations where an application cannot be written entirely in Java [ 1 ].

Common native library formats include .dll files on Windows, .so files on Linux and .dylib files on macOS platforms. The conventional idiom for loading these libraries in Java is presented in the code example below.

package rollbar;
public class ClassWithNativeMethod {
    static {
    System.loadLibrary("someLibFile");
    native void someNativeMethod(String arg);
    /*...*/

Java loads native libraries at runtime by invoking the System.load() or the System.loadLibrary() method. The main difference between the two is that the latter doesn’t require the absolute path and file extension of the library to be specified—it relies on the java.library.path system property instead. To access native methods from the loaded libraries, method stubs declared with the native keyword are used.

UnsatisfiedLinkError Error: What is It & When does It Happen?

If a Java program is using a native library but is unable to find it at runtime for some reason, it throws the java.lang.UnsatisfiedLinkError runtime error. More specifically, this error is thrown whenever the JVM is unable to find an appropriate native-language definition of a method declared native, while attempting to resolve the native libraries at runtime [2]. The UnsatisfiedLinkError error is a subclass of the java.lang.LinkageError class which means this error is captured at program startup, during the JVM’s class loading and linking process.

Some commonly encountered situations where this error occurs include a reference to the ocijdbc10.dll and ocijdbc11.dll libraries when trying to connect to an Oracle 10g or 11g database with the OCI JDBC driver [3], as well as dependence on the lwjgl.dll library used in game development and Java applications relying on some core legacy C/C++ libraries [4].

How to Handle the UnsatisfiedLinkError Error

To figure out the exact culprit and fix the UnsatisfiedLinkError error, there are a couple of things to consider:

  • Make sure that the library name and/or path are specified correctly.
  • Always call System.load() with an absolute path as an argument.
  • Make sure that the library extension is included in the call to System.load().
  • Verify that the java.library.path property contains the location of the library.
  • Check whether the PATH environment variable contains the path to the library.
  • Run the Java program from a terminal with the following command: java -Djava.library.path="<LIBRARY_FILE_PATH>" -jar <JAR_FILE_NAME.jar>
  • An important thing to keep in mind is that System.loadLibrary() resolves library filenames in a platform-dependent way, e.g. the code snippet in the example in the Introduction would expect a file named someLibFile.dll on Windows, someLibFile.so on Linux, etc.

    Also, the System.loadLibrary() method first searches the paths specified by the java.library.path property, then it defaults to the PATH environment variable.

    UnsatisfiedLinkError Error Example

    The code below is an example of attempting to load a native library called libraryFile.dll with the System.loadLibrary() method on a Windows OS platform. Running this code throws the UnsatisfiedLinkError runtime error with a message that reads “no libraryFile in java.library.path” suggesting that the path to the .dll library could not be found.

    package rollbar;
    public class JNIExample {
     static {
       System.loadLibrary("libraryFile");
     native void libraryMethod(String arg);
     public static void main(String... args) {
       final JNIExample jniExample = new JNIExample();
       jniExample.libraryMethod("Hello");
    
    Exception in thread "main" java.lang.UnsatisfiedLinkError: no libraryFile in java.library.path: C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files (x86)\Common Files\Intel\Shared Files\cpp\bin\Intel64;C:\ProgramData\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\MySQL\MySQL Utilities 1.6\;C:\Program Files\Git\cmd;C:\Program Files (x86)\PuTTY\;C:\WINDOWS\System32\OpenSSH\;...
        at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2447)
        at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:809)
        at java.base/java.lang.System.loadLibrary(System.java:1893)
        at rollbar.JNIExample.<clinit>(JNIExample.java:6)

    There are a couple of approaches to fixing this error.

    Approach #1: Updating the PATH environment variable

    One is to ensure that the PATH environment variable contains the path to the libraryFile.dll file. In Windows, this can be done by navigating to Control Panel → System Properties → Advanced → Environment Variables, finding the PATH variable (case insensitive) under System Variables, and editing its value to include the path to the .dll library in question. For instructions on how to do this on different operating systems, see [5].

    Approach #2: Verifying the java.library.path property

    Another approach is to check whether the java.library.path system property is set and if it contains the path to the library. This can be done by calling System.getProperty("java.library.path") and verifying the content of the property, as shown in the code below.

    package rollbar;
    public class JNIExample {
     static {
       var path = System.getProperty("java.library.path");
       if (path == null) {
         throw new RuntimeException("Path isn't set.");
       var paths = java.util.List.of(path.split(";"));
       //paths.forEach(System.out::println);
       if (!paths.contains("C:/Users/Rollbar/lib")) {
         throw new RuntimeException("Path to library is missing.");
       System.loadLibrary("libraryFile");
     native void libraryMethod(String arg);
     public static void main(String... args) {
       final JNIExample jniExample = new JNIExample();
       jniExample.libraryMethod("Hello");
    
    Exception in thread "main" java.lang.ExceptionInInitializerError
    Caused by: java.lang.RuntimeException: Path to library is missing.
        at rollbar.JNIExample.<clinit>(JNIExample.java:16)

    Technically, the java.library.path property can be updated by calling System.setProperty("java.library.path", "./lib"), but since system properties get loaded by the JVM before the class loading phase, this won’t have an effect on the System.loadLibrary("libraryFile") call that tries to load the library in the example above. Therefore, the best way to solve the issue is by following the steps outlined in the previous approach.

    Approach #3: Overriding the java.library.path property

    As an addendum to the previous approach, the only effective way to explicitly set the java.library.path property is by running the Java program with the -Dproperty=value command line argument, like so:

    java -Djava.library.path="C:\Users\Rollbar\lib" -jar JNIExample

    And since this would override the system property if already present, any other libraries required by the program to run should also be included here.

    Approach #4: Using System.load() instead of System.loadLibrary()

    Lastly, replacing System.loadLibrary() with a call to System.load() which takes the full library path as an argument is a solution that circumvents the java.library.path lookup and fixes the problem regardless of what the initial cause for throwing the UnsatisfiedLinkError error was.

    package rollbar;
    public class JNIExample {
     static {
       System.load("C:/Users/Rollbar/lib/libraryFile.dll");
     native void libraryMethod(String arg);
     public static void main(String... args) {
       final JNIExample jniExample = new JNIExample();
       jniExample.libraryMethod("Hello");
       System.out.println("Library method was executed successfully.");
    
    Library method was executed successfully.

    Hardcoding the path to the library might not be always desirable, however, so resorting to the other approaches might be preferable in those scenarios.

    Summary

    Using native libraries compiled for different platforms is a common practice in Java, especially when working with large and feature- or performance-critical systems. The JNI framework enables Java to do this by acting as a bridge between Java code and native libraries written in other languages. One of the issues programmers run into is failure to load these native libraries in their Java code correctly, at which point the UnsatisfiedLinkError runtime error is being triggered by the JVM. This article provides insight into the origins of this error and explains relevant approaches for dealing with it.

    Track, Analyze and Manage Errors With Rollbar

    ![Rollbar in action](https://rollbar.com/wp-content/uploads/2022/04/[email protected])

    Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Java errors easier than ever. Sign Up Today!

    References

    [1] Oracle, 2021. Java Native Interface Specification Contents, Introduction. Oracle and/or its affiliates. [Online]. Available: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/intro.html. [Accessed Jan. 11, 2022]

    [2] Oracle, 2021. UnsatisfiedLinkError (Java SE 17 & JDK 17). Oracle and/or its affiliates. [Online]. Available: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/UnsatisfiedLinkError.html. [Accessed Jan. 11, 2022]

    [3] User 3194339, 2016. UnsatisfiedLinkError: no ocijdbc11 in java.library.path. Oracle and/or its affiliates. [Online]. Available: https://community.oracle.com/tech/developers/discussion/3907068/unsatisfiedlinkerror-no-ocijdbc11-in-java-library-path. [Accessed Jan. 11, 2022]

    [4] User GustavXIII, 2012. UnsatisfiedLinkError: no lwjgl in java.library.path. JVM Gaming. [Online]. Available: https://jvm-gaming.org/t/unsatisfiedlinkerror-no-lwjgl-in-java-library-path/37908. [Accessed Jan. 11, 2022]

    [5] Oracle, 2021. How do I set or change the PATH system variable?. Oracle and/or its affiliates. [Online]. Available: https://www.java.com/en/download/help/path.html. [Accessed Jan. 11, 2022]