Java Native Interface (JNI)

JNI is a programming framework that enables the java code running in a java virtual machine to call native applications specific to 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 with 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 lobrary hello.dll in windows and libhello.so in unix systems during the class loading. The library should be avalliable in the java’s library path otherwise it will throw UnsatisfiedLinkError. You can include the library in the 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 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 allocate an instance of HelloJNI and invoke 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.



Author: InApp
We are a custom software development company offering Testing Services, Application Development, Mobility Solutions & more. Customers: Startups - Fortune 500

1 Comment

Leave a Reply

3 × four =