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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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]