Java Exception Handling

Java Exception Handling – UnsatisfiedLinkError

Moving along through our in-depth Java Exception Handling series, in today’s article we’ll be looking over the UnsatisfiedLinkError, which is thrown when attempting to dynamically load a native library that cannot be located by the Java Runtime Environment (JVM).

We’ll examine the UnsatisfiedLinkError by looking at where it resides in the overall Java Exception Hierarchy, as well as exploring some functional sample code illustrating how one might load native libraries during runtime, and how that might lead to UnsatisfiedLinkErrors. Let’s get going!

The Technical Rundown

All Java errors implement the java.lang.Throwable interface, or are extended from another inherited class therein. The full exception hierarchy of this error is:

Full Code Sample

Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.

Note: As mentioned in the code documentation, some code used in this sample was obtained from this StackOverflow comment.

When Should You Use It?

To understand why an UnsatisfiedLinkError might be thrown, we should first briefly talk about native libraries in Java. Most code that is created and executed within a given Java application is written using Java code, which can then be interpreted by the JVM to create a running application. Additionally, the Java Native Interface (JNI) was introduced to support code written in other programming languages, which can then be interpolated and run alongside standard Java code. For example, a library written and compiled in the C programming language could be converted into a native .dll file that most Windows users are familiar with, and this “native library” can then be loaded by the JNI and executed within a normal Java application.

Now, the potential for a thrown UnsatisfiedLinkError occurs when attempting to load such a native library that doesn’t exist, or is otherwise incompatible with the executing Java application. To illustrate, our sample code is somewhat complex, but much of it is broken up into a series of helper classes. Thus, we start with the simple listLoadedLibraries() method, which does just as the name suggests, listing all currently loaded native libraries:

Executing the above outputs the following, showing that my current JVM isn’t running much in the way of additional libraries:

Now, you may run into a scenario where you wish to dynamically unload an already-loaded library. There isn’t a direct API method that allows for this, because the JVM instead only unloads classes loaded by a class loader when garbage collection takes place. For example, the following unloadLibraryByName(String libraryName, String methodName) method attempts to unload the passed library by assigning it to a new class loader, then nullifying it and performing garbage collection:

Since we only have the zip library currently loaded, let’s see what happens if we try to unload it:

Attempting to unload the java.util.zip library above actually produces a SecurityException, indicating that the java.util.zip package name is prohibited:

This particular restriction is intended to prevent user code from modifying standard Java packages, which could potentially present significant security threats, since the native classes have very low-level system access. Therefore, while the unloadLibraryByName(...) method can be used to unload a custom native library, it can’t unload a standard Java package, as we saw above.

Alright, so unloading a native library is all well and good, but how do we actually load a library? There is actually an API method for that, as we can see in the loadLibraryByName(String name) method:

Simply calling System.loadLibrary(String libname) will attempt to load the passed native library file (.dll, .so, etc). To illustrate, let’s try loading a native library:

As you may suspect, attempting to load a library named InvalidLibrary throws an UnsatisfiedLinkError, indicating that such a library cannot be found in the java.library.path:

The Airbrake-Java library provides real-time error monitoring and automatic exception reporting for all your Java-based projects. Tight integration with Airbrake’s state of the art web dashboard ensures that Airbrake-Java gives you round-the-clock status updates on your application’s health and error rates. Airbrake-Java easily integrates with all the latest Java frameworks and platforms like Spring, Maven, log4j, Struts, Kotlin, Grails, Groovy, and many more. Plus, Airbrake-Java allows you to easily customize exception parameters and gives you full, configurable filter capabilities so you only gather the errors that matter most.

Check out all the amazing features Airbrake-Java has to offer and see for yourself why so many of the world’s best engineering teams are using Airbrake to revolutionize their exception handling practices!