a beginner’s guide to java native interface (JNI)
There are situations we need to directly invoke functions from other programming languages (such as C, C++ & Fortran) in Java. This post takes you through such an example written in C++. Assume the C++ code resides in a shared library called native.dll
.
Pre-requisites:
- JDK
- C++ Compiler (we use MinGW)
1. set the VM argument
before we start writing any code, we have to setup a VM argument which would instruct our java program where to look for the dll file (native lib).
2. Define the skeleton of the Java class:
Let’s assume our C++ library has a function called print()
& it accepts a string parameter. Keeping it in mind, we can write our java class.
but now if we try to run this, we get an error. the JVM (java virtual machine) can’t find (or load) a file called native.dll
. This was expected :)
Note: the signature of the print function uses the native
keyword. Going forward, every command that is mentioned in this post will be executed from the folder where Main.java resides.
3. Generate the header file
we need to generate a header file with the native function that was declared above. We use javac
command with -h
flag for this. This command will work with Java 9 & above. Prior versions use javah
instead. This would create 2 files:com_hamzeen_jni_labs_Main.h
& Main.class.
javac -h . Main.java
4. The C++ class
provide an implementation for the print() method. we use a cout
(character output) statement to output a string to the console followed by the length of characters the function receives as parameter.
file name: com_hamzeen_jni_labs_Main.cpp
#include <iostream>
#include "com_hamzeen_jni_labs_Main.h"
JNIEXPORT void JNICALL Java_com_hamzeen_jni_1labs_Main_print
(JNIEnv* env, jobject thisObject, jstring param) {
std::cout << "Hello from C++ !!" << env->GetStringUTFLength(param) << std::endl;
}
5. Compile & Link
now it’s time to compile the C++ code and then link it. This is where we need a C++ compiler. Here we will generate 2 more files: com_hamzeen_jni_labs_Main.o
& native.dll.
compile the C++ code:
g++ -c -m64 -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_hamzeen_jni_labs_Main.cpp -o com_hamzeen_jni_labs_Main.o
create the shared library native.dll
. This is the file JVM needs.
g++ -shared -o native.dll com_hamzeen_jni_labs_Main.o -Wl,--add-stdcall-alias
5. The final code & output
now the java program can invoke the function from the native (C++) library.
/**
* JNI Demo Class in Java
* @author Hamzeen
*/
public class Main {
static {
// native.dll
System.loadLibrary("native");
}
public native void print(String param);
public static void main(String[] args) {
Main instance = new Main();
instance.print("hello world!");
}
}