Java Native Interface (JNI), part of the Java platform, is an interface that enables the communication between Java applications running on a Java Virtual Machine (JVM) and native applications or libraries written in other programming languages (e.g. C, C++).
JNI provides improved performance in some low-level tasks (e.g. Math.sqrt (double a)) and enables communication with hardware devices (Bluetooth, Wi-Fi, etc.). However, there is a disadvantage in losing platform independence because such a program uses the library compiled for specific operating system.
The figure above shows the implementation of a native library and its integration with Java. The example demonstrates how to call C library that prints the text “Hello World from C function!” from Java application. The entire implementation process can be summarized into several steps:
- Create a class that declares the native methods
public class HelloWorld { static { // load the C-library System.loadLibrary("HelloWorld"); } // declaration of native method private native void print(); public static void main(String[] args) { new HelloWorld().print(); } }- loadLibrary(String libname) method is used to load an external C-library; libname represents the path to the library.
- Placing the call in a static initialization block ensures that the library is only loaded once per class. The static initialization block is executed immediately after the class is loaded into memory.
- The keyword native is used to denote native methods; the methods created in C-library, which will be called.
- Compile the Java program
- In NetBeans IDE, right-click the project name and select Clean and Build from the context menu. The .class files will be created in the “build\classes” folder in the project directory.
- Outside of IDE, use an external javac tool.
- Generate the header file
- To generate a C-header file (.h) with a native function declaration use the javah tool (part of JDK, typically in C:\Program Files\Java\jdk\bin) on the Java .class file. Enter the file name without .class extension:
javah -jni HelloWorld
- The generated header file contains a declaration of C-function that is linked with the Java native method:
JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);
- To generate a C-header file (.h) with a native function declaration use the javah tool (part of JDK, typically in C:\Program Files\Java\jdk\bin) on the Java .class file. Enter the file name without .class extension:
- Write the C implementation of the native methods
- In NetBeans IDE, select New Project → C/C++ Dynamic Library.
- Created project must be linked with JNI libraries:
- Right-click the project name and select Properties from the context menu.
- On the Project Properties page, select the C Compiler section, and type paths to JNI in the Include Directories box (typically C:/Program Files/Java/jdk/lib and C:/Program Files/Java/jdk/include/win32).
- In the same section C Compiler, in the Additional Options box type:
-Wl,--add-stdcall-alias -mno-cygwin -shared -m32 -Wall -pedantic
- -Wl,–add-stdcall-alias passes option –add-stdcall-alias to the linker. The option sets alias for the function names without the addition of @nn.
- -mno-cygwin ensures independence from cygwin.dll on the Windows environment (when using Cygwin gcc).
- -shared option tells the compiler to generate a dynamic library instead of an executable file.
- -m32 option tells the compiler to create a 32b binary (required only when using 64b GCC and 32b JDK).
- -Wall -pedantic ensures print of all warning messages and source code control to ANSI standards.
- Copy the generated header file to the created project directory and link it to the project (right-click the Header Files node, select Add Existing Item from the context menu).
- Implement methods, right-click the Source Files node, select New and then C Source File.
- Edit the created file by typing the following code:
#include <jni.h> #include <stdio.h> #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) { printf("Hello World from C function!\n"); }
- Compile the dynamic library
- Right-click the project name and select Clean and Build.
- The dynamic library file (.dll for Windows, .so for Unix) will be created in the “dist” folder in the project directory.
- Run the program using the java runtime interpreter
- Copy the generated library (.dll or .so) to the Java project directory or to the directory where the executable file is.
- If the library is in another directory, the path must be defined in the loadLibrary(String libname) method.
- Run the Java application, and the output prints the text “Hello World from C function!” as defined in C.
More information about JNI can be found in the book Java Native Interface: Programmer’s Guide and Specification.
