Java Native Interface: JNI Example



JNI is an interface that allows Java to interact with code written in another language. Motivation for JNI is code reusability and performance. WIth JNI, you can reuse existing/legacy code with Java (mostly C/C++). In terms of performance, native code used to be up to 20 times faster than Java, when running in interpreted mode. Modern JIT compilers (HotSpot) make this a moot point.

JNI can also be used to invoke Java code from within natively-written applications - such as those written in C/C++.
In fact, the java command-line utility is an example of one such application, that launches Java code in a Java Virtual Machine.

JNI Components

javah is a JDK tool that builds C-style header files from a given Java class that includes native methods. It adapts Java method signatures to native function prototypes

jni.h is a C/C++ header file included with the JDK that maps Java types to their native counterparts. javah automatically includes this file in the application header files.

JNI data type mapping in variables

Code:

boolean jboolean
byte jbyte
char jchar
double jdouble
float jfloat
int jint
long jlong
short jshort
void void

JNI Development - Java Part

1. Create a Java class with native method(s):
public native void sayHi(String who, int times);

2. Load the library which implements the method:
System.loadLibrary("HelloImpl");

3. Invoke the native method from Java

For example, our Java code could look like this:

Code:

public class Hello {
public native void sayHi(String who, int times);
static { System.loadLibrary("HelloImpl"); }
public static void main (String[] args) {
Hello hello = new Hello();
hello.sayHi(args[0], Integer.parseInt(args[1]));
}
}

The method sayHi will be implemented in C/C++ in separate file(s), which will be compiled into a library. The library filename will be called libHelloImpl.so (on Unix) or HelloImpl.dll (on Windows), but when loaded in Java, the library has to be loaded as HelloImpl.


JNI Development - C Part

1. We use the JDK javah utility to generate the header file Hello.h with a function prototype for sayHi method:

Code:

javac Hello.java
javah -jni Hello

2. We then create Hello.c to implement the sayHi function.

The file Hello.h looks like:

Code:

...
#include <jni.h>
...
JNIEXPORT void JNICALL Java_Hello_sayHi (JNIEnv *, jobject, jstring, jint);
...

The file Hello.c looks like:

Code:

#include <stdio.h>
#include "Hello.h" // generated by javah

JNIEXPORT void JNICALL Java_Hello_sayHi
(JNIEnv *env, jobject obj, jstring who, jint times) {
jint i;
jboolean iscopy;
const char *name;
name = (*env)->GetStringUTFChars(env, who, &iscopy);
for (i = 0; i < times; i++) {
printf("Hello %s\n", name);
}
}

Compiling

We are now ready to compile our program and run it. The compilation is system-dependent. This will create libHelloImpl.so or HelloImpl.dll (depending on the O/S). Set LD_LIBRARY_PATH to point to the directory where the compiled library is stored. Run your Java application.

For example, to compile Hello.c on Linux do:

Code:

gcc -o libHelloImpl.so -lc -shared \
-I/usr/local/jdk1.6.0_03/include \
-I/usr/local/jdk1.6.0_03/include/linux Hello.c

Then set the LD_LIBRARY_PATH to the current working directory: export LD_LIBRARY_PATH=.

Finally, run your application:

Code:

java Hello Student 5
Hello Student
Hello Student
Hello Student
Hello Student
Hello Student

Common mistakes resulting in java.lang.UnsatisfiedLinkError usually come from incorrect naming of the shared library (O/S- dependent), the library not being in the search path, or wrong library being loaded by Java code.

Published November 25, 2009