Java Native Interface (Java JNI)

What is Java Native Interface (Java JNI)?

Java JNI is a programming framework that enables the Java native code running in a Java virtual machine to call native applications specific to the operating system and hardware. JNI enables one to write native methods to handle situations when an application cannot be written entirely in the Java programming language.

Here I am describing how to do programming with JNI with an example. JNI is difficult, as it involves two languages and runtimes. I shall assume that you are familiar with:

  1. Java
  2. C/C++ and the GCC Compiler
  3. (For Windows) Gygwin or MinGW.
  4. (For IDE) Eclipse C/C++ Development Tool (CDT)

Here, I am giving an example of C programming language.

Step 1: Write a Java class that uses native methods

public class HelloJNI { static { System.loadLibrary(“hello”); /* hello.dll (Windows) or libhello.so (Unixes)*/ } /* A native method that receives nothing and returns void*/ private native void sayHello(); public static void main(String[] args) {

/* invoke the native method*/

new HelloJNI().sayHello(); } }

Here we can see a static block, which will load the library hello.dll in Windows and libhello.so in unix systems during the class loading. The library should be available in the java’s library path otherwise it will throw UnsatisfiedLinkError. You can include the library in Java’s library path via VM argument,
-Djava.library.path=path_to_lib.

Next, we declare the method sayHello() as a native instance method, via the keyword native, which denotes that this method is implemented in another language. A native method does not contain a body. The sayHello() is contained in the native library loaded.

The main() method allocates an instance of HelloJNI and invokes the native method sayHello().

Step 2: Compile the java file

javac HelloJNI.java

This will create HelloJNI.class file.
Step 3: Create the C/Header file – HelloJNI.h

Using javah utility, we can create header file for the corresponding HelloJNI class.

javah HelloJNI

It will generate the following file HelloJNI.h

/* DO NOT EDIT THIS FILE – it is machine generated */ #include <jni.h> /* Header for class HelloJNI */ #ifndef _Included_HelloJNI #define _Included_HelloJNI #ifdef __cplusplus extern “C” { #endif /* * Class: HelloJNI * Method: sayHello * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloJNI_sayHello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif

Here, it defines a C function Java_HelloJNI_sayHello as follows

JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject);

The naming convention for C function is Java_{package_and_classname}_{function_name}(JNI arguments). The dot in package name shall be replaced by underscore.

The arguments:

  • JNIEnv*: reference to JNI environment, which lets you access all the JNI fucntions.
  • jobject:reference to “this” Java object

The extern “C” is recognized by C++ compiler only. It notifies the C++ compiler that these functions are to be compiled using C’s function naming protocol (instead of C++ naming protocol). C and C++ have different function naming protocols as C++ support function overloading and uses a name mangling scheme to differentiate the overloaded functions.

Step 4: C Implementation – HelloJNI.c

#include <jni.h> #include <stdio.h> #include “HelloJNI.h” JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) { printf(“Hello World!\n”); return; } save this file as “HelloJNI.c”.

The header “jni.h” is available under the “JAVA_HOME>\include” and “<JAVA_HOME>\include\win32″ directories, where <JAVA_HOME> is your JDK installed directory (e.g., “c:\program files\java\jdk1.7.0″).

The C function will print “Hello World” in the console.

Compile this program depends on the C compiler you use.

gcc -Wl,–add-stdcall-alias -I”<JAVA_HOME>\include” -I”<JAVA_HOME>\include\win32″ -shared -o hello.dll HelloJNI.c

The compiler options used are:

  • -Wl: The -Wl to pass linker option –add-stdcall-alias to prevent UnsatisfiedLinkError (symbols with a stdcall suffix (@nn) will be exported as-is and also with the suffix stripped). (Some people suggested to use -Wl,–kill-at.)
  • -I: for specifying the header files directories. In this case “jni.h” (in “<JAVA_HOME>\include”) and “jni_md.h” (in “<JAVA_HOME>\include\win32″), where <JAVA_HOME> denotes the JDK installed directory. Enclosed the directory in double quotes if it contains spaces.
  • -shared: to generate share library.
  • -o: for setting the output filename “hello.dll”.

You can also compile and link in two steps:

// Compile-only with -c flag. Output is HElloJNI.o

> gcc -c -I”<JAVA_HOME>\include” -I”<JAVA_HOME>\include\win32″ HelloJNI.c

// Link into shared library “hello.dll”

> gcc -Wl,–add-stdcall-alias -shared -o hello.dll HelloJNI.o

Step 5:Run the Java Program

java HelloJNI

or

java -Djava.library.path=. HelloJNI

You may need to specify the library path of the “hello.dll” via VM option -Djava.library.path=<path_to_lib>, as shown above.

Have questions? Contact the technology experts at InApp to learn more.