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

  1. Create a native method in a Java class.
  2. 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.