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:

  • The file path is passed as string, not as instance of File. It is because File transforms the abstract path to system-specific (absolute path decision, directory delimiters) one, which could cause problems. It must be an absolute path (starting with '/') and the filename has to be at least three characters long (due to restrictions of File.createTempFile(String prefix, String suffix).
  • The temporary file is stored into temp directory specified by java.io.tmpdir (by default it's the operating system's temporary directory). It should be automatically deleted when the application exits.
  • Although the code has some try-finally section (to be sure that streams are closed properly in case an exception is thrown), it does not catch exceptions. The exception has to be handled by the application. I belive this approach is cleaner and has some benefits.

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 Widnows.

Get the whole code from my Github!

Posted on . Bookmark the permalink.