Tuesday, March 29, 2011

Java Native Interface

Java Native Methods

The native modifier indicates that a method is implemented in platform-dependent code, often in C / C++. Native is a modifier and a reserved keyword and that native can be applied only to methods. Note that a native method's body must be a semicolon (;) (like abstract methods), indicating that the implementation is omitted.

Pros and cons
The ability to write just one set of code in Java and have it run on every system with a Java run-time is one of Java's primary strengths. But this platform independence has one key drawback: What do we do with the vast amount of existing code? The trick is to use the so-called native method interface (JNI).

Writing native methods involves importing code from other programming language (eg. C code) into your Java application.

Step-by-step guide
In the example we will use C language and linux/unix host platform. The steps are:
* Write Java code
* Compile Java code
* Create C header (.h file)
* Create C stubs file
* Write C code
* Create shared code library (or DLL)
* Run application

Example Java code
class JavaPrinter {
    public native void printText();
    static
    {
       System.loadLibrary( "nativeprinter" );   
           // Attention: Note lowercase of library name
    }

    public static void main (String[] args) {
       JavaPrinter p = new JavaPrinter();
       p.printText();
    }
}

Compile the Java code
javac JavaPrinter.java

Create a C header file
javah JavaPrinter

Create a C source file
javah -stubs JavaPrinter

Add C/C++ code
Now, let's write the actual code to print out our greeting. By convention we put this code in a file named after our Java class with the string "Imp" appended to it. This results in JavaPrinterImp.c. Place the following into JavaPrinterImp.c:
#include   // Standard native method stuff.
#include "JavaPrinter.h"   // Generated before.
#include          // Standard C IO
void JavaPrinter_printText (struct HJavaPrinter *this) {
    puts ("Hi from C language!!!");
} 

Create a shared library
This is for GCC compiler. First, compile the C source files that we have already created. You have to tell the compiler where to find the Java native method support files, but the main trick here is that you have to explicitly tell the compiler to produce Position Independent Code (PIC):

gcc -I/usr/local/java/include -I/usr/local/java/include/genunix -fPIC -c JavaPrinter.c JavaPrinterImp.c

ow, create a shared library out of the resulting object (.o) files with the following magical incantation:

gcc -shared -Wl,-soname,libnativeprinter.so.1 
-o libnativeprinter.so.1.0 JavaPrinter.o JavaPrinter.o

Copy the shared library file to the standard short name:

cp libnativeprinter.so.1.0 libnativeprinter.so

JNI notes:
* subtle errors in the use of JNI can destabilize the entire JVM in ways that are very difficult to reproduce and debug.
* only applications and signed applets can invoke JNI.
* an application that relies on JNI loses the platform portability Java offers.
* the JNI framework does not provide any automatic garbage collection for non-JVM memory resources allocated by code executing on the native side. Consequently, native side code must assume the responsibility for explicitly releasing any such memory resources that it itself acquires.
* error checking is a MUST or it has the potential to crash the JNI side and the JVM.

No comments:

Post a Comment