Java Fundamentals Tutorial_ Java Native Interface (JNI)
Java Fundamentals Tutorial_ Java Native Interface (JNI)
Code reusability
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
Allow Java to tap into low level O/S, H/W routines
JNI code is not portable!
Note
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.
package com.marakana.jniexamples;
static { System.loadLibrary("HelloImpl"); } //
The method sayHi will be implemented in C/C++ in separate le(s), which will be compiled into a library.
The library lename will be called libHelloImpl.so (on Unix), HelloImpl.dll (on Windows) and
libHelloImpl.jnilib (Mac OSX), but when loaded in Java, the library has to be loaded as HelloImpl .
...
#include <jni.h>
...
JNIEXPORT void JNICALL Java_com_marakana_jniexamples_Hello_sayHi
(JNIEnv *, jobject, jstring, jint);
...
#include <stdio.h>
#include "com_marakana_jniexamples_Hello.h"
For example, to compile com_marakana_jniexamples_Hello.c in the "classes" directory (if your .h le and .c
le are there) on Linux do:
On Mac OSX :
export LD_LIBRARY_PATH=.
Finally, run your application in the directory where your compiled classes are stored ("classes" for example):
Note
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.
However, primitive and reference types are treated di erently in JNI
Mapping for objects is more complex. Here we will focus only on strings and arrays but before we dig
into that let us talk about the native methods arguments
package com.marakana.jniexamples;
static { System.loadLibrary("helloname"); }
...
#include <jni.h>
...
JNIEXPORT void JNICALL Java_com_marakana_jniexamples_HelloName_sayHelloName
(JNIEnv *, jclass, jstring);
...
A .c le like this one would not produce the expected result:
#include <stdio.h>
#include "com_marakana_jniexamples_HelloName.h"
JNIEnv *env : Is a pointer that points to another pointer pointing to a function table (array of pointer).
Each entry in this function table points to a JNI function. These are the functions we are going to use for
type conversion
The second argument is di erent depending on whether the native method is a static method or an
instance method
Instance method: It will be a jobject argument which is a reference to the object on which the
method is invoked
Static method: It will be a jclass argument which is a reference to the class in which the method
is de ne
If you remember the previous example, we had a native method where we wanted to display "Hello name":
#include <stdio.h>
#include "com_marakana_jniexamples_HelloName.h"
This example would not work since the jstring type represents strings in the Java virtual machine. This
is di erent from the C string type ( char * )
Here is what you would do, using UTF-8 string for instance:
#include <stdio.h>
#include "com_marakana_jniexamples_HelloName.h"
This returns a pointer to an array of bytes representing the string in UTF-8 encoding (without making a
copy)
When we are not making a copy of the string, calling ReleaseStringUTFChars prevents the memory
area used by the string to stay "pinned". If the data was copied, we need to call
ReleaseStringUTFChars to free the memory which is not used anymore
Here is another example where we would construct and return a java.lang.String instance:
#include <stdio.h>
#include "com_marakana_jniexamples_GetName.h"
We are going to see an example of how to read a Java primitive array in the native world
First, this would be your Java program:
package com.marakana.jniexamples;
This method will return the sum of each element in the array
After running javah , create your .c le that would look like this:
#include <stdio.h>
#include "com_marakana_jniexamples_ArrayReader.h"
We could also have used GetIntArrayRegion since we exactly know the size of the array
We could imagine a utility function like this one:
Throw the exception using the class reference we got before and the message for the exception
ThrowExceptionByClassName(env,"java/lang/IllegalArgumentException","This exception is
From this Java class, we will see how to call its methods or access its properties in the native code:
package com.marakana.jniexamples;
//Native method
public native void propertyAccess(); //
public native void methodAccess(); //
//Load library
static {
System.loadLibrary("instanceaccess");
}
}
Name property that we are going to modify along this code execution
This method will be called by the native code to modify the name property
This native method modi es the name property by directly accessing the property
This native method modi es the name property by calling the Java method setName()
This would be our C code for native execution:
#include <stdio.h>
#include "com_marakana_jniexamples_InstanceAccess.h"
/* Getting a jstring */
jstr = (*env)->GetObjectField(env, object, fieldId); /* */
This is getting a reference to the object class
Gets a eld Id from the object class, specifying the property to get and the internal type. you can nd
information on the jni type there:
http://download.oracle.com/javase/6/docs/technotes/guides/jni/spec/types.html
This will return the value of the property in the native type: here a jstring
This creates a new java.lang.String that is going be use to change the value of the property
Gets a method id from the object class previously obtained, specifying the name of the method along
with its signature. There is a very useful java tool that you can use to get the signature of a method:
javap -s -p ClassName for instance javap -s -p InstanceAccess
This creates a new java.lang.String that we are going to use as an argument when calling the java method
from native code
Calling CallVoidMethod since the Java method return type is void and we are passing the previously
created jstring as a parameter
Prev Next
Home | ToC