Adam Heinrich

How to Load Native JNI Library from JAR

The JNI (Java Native Interface) is a framework that provides a bridge between Java and native applications. Java applications can define native methods which are implemented in dynamic library written in other languages such as C or C++. The dynamic library is able to call both static and dynamic methods. More information about JNI can be found on Wiki or in tutorial Beginning JNI with NetBeans (for Linux).

The problem is that for loading such a dynamic library you have to call method System.load(String filename) which requires an absolute filename. This approach is just fine if you have dynamic library outside the application’s JAR archive, but when bundling dynamic library within the JAR it is necessary to extract the library into filesystem before loading it. And that’s exactly what my code does.

Our simple JNI class could look like this:

public class HelloJNI {
    static {
        System.load("/path/to/my/library.so");
    }

    public native void hello();
}

To extract the library before loading it it’s necessary to add some code into the static section. I wrapped it into a static method inside simple class called NativeUtils. I decided to put it into separate class in order to have space for adding more features (like choosing the right dynamic library for host OS and architecture). The class can be found on my Github.

The code is commented and self-explaining, so I don’t have to write too much about it. Just three notes:

Final usage is pretty simple. :-) Just call method loadLibraryFromJar and handle exception somehow:

import cz.adamh.NativeUtils;
public class HelloJNI {
  static {
    try {
      NativeUtils.loadLibraryFromJar("/resources/libHelloJNI.so");
    } catch (IOException e) {
      e.printStackTrace(); // This is probably not the best way to handle exception :-)
    }
  }

  public native void hello();
}

Edited 2013-04-02: Lofi came with a workaround to release and delete our DLL from temporary directory on Windows.

Get the whole code from my Github!

Comments

The comments have been archived from Disqus.

davs on 2012-12-27:

The article is great.
One little remark ..

Lines 60-61:
// Prepare temporary file
File temp = File.createTempFile(prefix, suffix);

in your case suffix contain only extension (without '.' before) .. And I was getting the error of FileNotFound in line 91.

Changing Line 61 to
File temp = File.createTempFile(prefix, "." + suffix);
fixed my issue .. maybe not only mine :)

Cheers,
Davs

Adam on 2012-12-27:

Thank you, davs. Sorry for my fault, the temporary file was really "libraryso" instead of "library.so". But I didn't have any problems caused by the FileNotFound with my code, maybe it was some OS-specific issue (I run application using this code on Linux).

I modified line 52 from suffix = (parts.length > 1) ? parts[parts.length - 1] : null; to suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null;, because the File.createTempFile(prefix, suffix) method uses ".tmp" as default extension if suffix is null.

I also changed split() on line 50, it is now limited to 2 items.

Eveything should be OK now :-)

Adam on 2013-02-07:

Hello, this is interesting. Look at nice explanation at http://kalblogs.blogspot.cz..., maybe the $LD_LIBRARY_PATH variable could be the way to go.

Some people wanted to do the same thing (embed JNI library that depends on some shared libs into JAR), after some searching I found only this crazy solution: http://stackoverflow.com/a/......

Lars Nielsen on 2014-08-05:

Hey I am trying this with a folder tructure
/demo
--/src
----- App.java
----- /com.core
----- NativeUtils.java
--/Libs
----- libs.jar

with the App.java looking like this:

import java.io.IOException;

import com.core.NativeUtils;


public class App {


public static void main(String[] args) {
try {
NativeUtils.loadLibraryFromJar("/lib/lib_fifi.so");
System.out.println("Library Loaded - Loaded from jar");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

But it does not work any ideas I get: File /lib/lib_fifi.so was not found inside JAR

Adam on 2014-08-09:

Hello, it looks like you didn't include the file (I don't see any /lib/lib_fifi.so in your folder structure).

Aurélien on 2014-01-29:

Thanks, useful trick

Baruch Youssin on 2014-06-24:

A great solution, very simple, much simpler than all the competing solutions posted on the net.
There is one thing in this article that I do not understand: the issue of "absolute path (starting with ‘/’)".
This refers to the
path
parameter in the code, which indicates the native library as a resource inside the jar.
This far, I have worked only with audio files as resources, and their paths should not start with a slash / .
In fact, I have tried to specify audio files by a path starting with a slash, as /com/...; here com was the name of the top-level directory in the jar, and the rest of the path pointed to the file-resource. This did not work out (java could not find the resource), neither on Windows XP nor on Linux Ubuntu 12.04, both running a most recent java from Oracle.
Removing the initial slash resolves the problem: java finds the audio file.
I am going to try both ways with the native library; but what is the rule here?

Baruch Youssin on 2014-06-26:

I have found the answer:
loadLibraryFromJar calls java.lang.Class.getResourceAsStream(String) method while for audio files I use a different method, javal.lang.ClassLoader.getResource(String).
These two methods have different rules for path name resolution, and for this reason in getResource(..) I must use the path without the leading / while in getResourceAsStream(..) I must use the leading /.
Thanks for the nice code, it works!

Lofi on 2013-03-28:

Thank you very much for sharing this! However, there's a slight hickup in the solution: The temporary library won't get deleted on windows because the JVM still has a lock on it when it shuts down and invokes deleteOnExit(). The library should be "unloaded". Unfortunately that's currently not possible in Java.

In case anyone else runs into this issue of having their temporary folder flooded with DLLs, I came up with this workaround:

* in additon to the temporary DLL, also create a .lock file on which you also issue a deleteOnExit(). This file will get deleted when the JVM shuts down

* during startup search for all .dll files and delete those which don't have an accompanying ".lock" file

Not quite the proper solution, but unless this is fixed internally in Java it may be some workaround :-)

Here's some code in case someone wants to use it, just put it at the bottom of the loadLibraryFromJar method:

        final String libraryPrefix = prefix;
final String lockSuffix = ".lock";

// create lock file
final File lock = new File( temp.getAbsolutePath() + lockSuffix);
lock.createNewFile();
lock.deleteOnExit();

// file filter for library file (without .lock files)
FileFilter tmpDirFilter =
new FileFilter()
{
public boolean accept(File pathname)
{
return pathname.getName().startsWith( libraryPrefix) && !pathname.getName().endsWith( lockSuffix);
}
};

// get all library files from temp folder
String tmpDirName = System.getProperty("java.io.tmpdir");
File tmpDir = new File(tmpDirName);
File[] tmpFiles = tmpDir.listFiles(tmpDirFilter);

// delete all files which don't have n accompanying lock file
for (int i = 0; i < tmpFiles.length; i++)
{
// Create a file to represent the lock and test.
File lockFile = new File( tmpFiles[i].getAbsolutePath() + lockSuffix);
if (!lockFile.exists())
{
System.out.println( "deleting: " + tmpFiles[i].getAbsolutePath());
tmpFiles[i].delete();
}
}
Adam on 2013-04-02:

Lofi, thank you for this workaround, it will be useful!

Blackshues on 2015-01-25:

This workaround is very clean, and worked for me right out of the box. Thank you sir.

Harbour Porpoise on 2018-04-26:

Thanks so much, this saved the day!

Víctor Vanaclocha Cebrián on 2019-09-18:

I'm trying use this class in a Maven project.

-src/main/java
----app.java
..src/main/resources
----libraries
--------win32-x86-64
------------jni.dll

I'm calling the "loadLibraryFromJar()" method and I try this:

NativeUtils.loadLibraryFromJar("/resources/libraries/win32-x86-64/jni.dll");
NativeUtils.loadLibraryFromJar("/libraries/win32-x86-64/jni.dll");

The exception is as follows:
java.io.FileNotFoundException: File /resources/libraries/win32-x86-64/jni.dll was not found inside JAR.

I am generating a jar with the libraries inside the maven jar-project so that I only have one jar application. the libraries go inside the resources directory of the maven structure.

Any idea what is happening?
In my project there are the dll inside the jar and in my eclipse project.