C/C++ and Java are popular programming languages. The Java Native Interface (JNI) is a standard to integrate in a portable way C++ and Java code. JNI works both way i.e. C++ implementation can be called from JAVA and vice versa. This post discussed about calling C/C++ implementation from JAVA.
native keyword in JAVA
This keyword acts as a link between JAVA language and code written in different languages except JAVA. If native keyword is applied to a method, then that means method will be implemented using native code written in some other language (like C or C++). A method marked as native cannot have a body and should end with a semicolon as shown below. Native method works together with JNI.
[public|protected|private] native method();
So first you need to declare a native function inside your Java class with appropriate Request and Responses. Next load a System library (a .so file or a .dll file) that includes the implementation of this native function in C++.
Loading System Library
To call a C++ method from Java, follow below steps
- Create a native method in a Java class.
- Load the system library (written in C/C++) using System.loadLibrary. Depending on the requirement, we can load this library in a static block so that it is available in our class.
// DateTimeUtils.java public class DateTimeUtils { // Declare native method public native String getSystemTime(); // Load system library static { System.loadLibrary("nativedatetimeutils"); } }
In the above example, dynamic link library nativedatetimeutils.so implements getSystemTime in C++.
The static initializer invokes System.loadLibrary() to load the native library nativedatetimeutils
during the class loading. It will be mapped to hello.dll
in Windows; or libhello.so
in Unix/Mac OS X. This library shall be included in Java’s library path (kept in Java system variable java.library.path). Otherwise program will throw a UnsatisfiedLinkError
if the library cannot be found in runtime.
Compiling Native Function
Starting from JDK 8, you should use “javac -h” to compile the Java program AND generate C/C++ header file as follows:
javac -h . DateTimeUtils.java
-h
option generates C/C++ header and places it in the directory specified (current directory in above example) directory.
Header file generated using above command should looks like as shown below
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class DateTimeUtils */ #ifndef _Included_DateTimeUtils #define _Included_DateTimeUtils #ifdef __cplusplus extern "C" { #endif /* * Class: DateTimeUtils * Method: getSystemTime * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_DateTimeUtils_getSystemTime (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
The naming convention for the C function is Java_{package_and_classname}_{function_name}(JNI_arguments). The arguments are:
- JNIEnv*: reference to JNI environment, which lets you access all the JNI functions.
- jobject: reference to “this” Java object.
Native Implementation
extern "C"
keyword notifies the C++ compiler that these functions are to be compiled using C’s function naming protocol instead of C++ naming protocol. Include the above header file and few other header file as shown in the below example.
// File : "DateTimeUtils.c" #include <jni.h> // JNI header provided by JDK #include <stdio.h> // C Standard IO Header #include "DateTimeUtils.h" // Generated // Implementation of the native method getSystemTime() JNIEXPORT void JNICALL Java_DateTimeUtils_getSystemTime(JNIEnv *env, jobject thisObj) { printf("Hello World!\n"); return; }
Compile the above program to generate a dynamic library which can be used in the JAVA program.
Example
Following example uses class declared in the previous section to get the current time.
public class DateTimeUtilsManualTest { public void givenNativeTime() { DateTimeUtils dateTimeUtils = new DateTimeUtils(); LOG.info("System time is : " + dateTimeUtils.getSystemTime()); assertNotNull(dateTimeUtils.getSystemTime()); } }
This example first creates a instance of DateTimeUtils, which will load the native library which we implemented above.