JNI Tutorial

28/12/2020

Java Native Interface (JNI) is a home-grown programming interface that’s bundled together with the Java Software Development Kit (SDK). JNI is critical because it allows developers to use code libraries or snippets of codes written in other programming languages such as C++ and C. An essential part of the JNI is the Invocation API which places a Java virtual machine (JVM) into applications written in native language so that developers can call the java code while still inside the native code.

Most developers are aware of performance and memory issues in Java.  To get around these problems, a programmer can use native language. As compared to Java, native code is up to 20 times faster when running in the interpreted mode. What’s more, using native code gives developers the chance to use previously incompatible hardware routines and low level operating systems.

What’s in this tutorial?

We will cover how to call native C/C++ code from inside a java app. To properly benefit from this tutorial, the following components and tools are needed.

  • The Java compiler javac.exe which comes integrated into the SDK.
  • The Java virtual machine (JVM) which is java.exe that also comes integrated into the SDK.
  • The native method C generator javah.exe that also ships with the SDK.
  • Native header files together with complete library files which are all used to define JNI.
  • Lastly, the C and C++ compiler whose role is to create a shared library. Here you can use either Visual C++ if you are working in a windows environment and cc when on a UNIX system.

JNI Components

Java Native Interface has two main components that give it all its capabilities and attributes. These are:

  • h: this is a C/C++ header file component that maps Java onto the native parts. Javah ensures this file is automatically added in the app header files.
  • javah: this is the tool that builds header files in C-style so that Java method signatures can be converted into native functions.

With these components in place, one can now start coding. We shall first look at calling C/C++ codes from Java applications.

Calling native code from Java applications

JNI allows the developer to exercise their creativity and go around problems that cannot be addressed in Java but can be solved in a native language. In such an instance JNI becomes an invaluable tool to the programmer in a couple of situations such as:

  • When you have legacy code libraries or code that you want to use inside a java program.
  • When you need to insert time-sensitive code in a faster, low-level programming language.
  • When you need to work with features that are platform dependent and are not supported in the Java class library.

Steps involved in calling C/C++ from Java code

Write the java code

This is the first step in this process. Here the developer is writing Java code to satisfy three components: declaring the native method which will be called later; loading the shared library which contains the native code; and finally calling the native methods. Using the following code, we will learn a few things:

  public class Example1    {      public native int intMethodName(int n);      public native boolean booleanMethodName(boolean bool);      public native String stringMethodName(String text);      public native int intArrayMethodName(int[] intArray);         public static void main(String[] args)      {       System.loadLibrary("Example1");       Example1 example = new Example1();       int square = example.intMethodName(5);       boolean bool = example.booleanMethodName(true);       String text = sample.stringMethodName("JAVA");       int sum = sample.intArrayMethodName(                        new int[]{1,1,2,3,5,8,13} );         System.out.println("intMethodName: " + square);       System.out.println("booleanMethodName: " + bool);       System.out.println("stringMethodName: " + text);       System.out.println("intArrayMethodName: " + sum);     }   }  

In lines 3 to 6, our native methods are declared. We must then load the shared libraries which is done on line 10 where finally the methods are called in lines 12 through 15.

Compiling the java code

The next step is compiling the java code to bytecode. We can do this by using the inbuilt javac java compiler which comes with the SDK. Here we use the following command to compile the code to bytecode:

javac Example1.java

Creating C/C++ header files

The third step is creating the native language header files which sources the native functions’ signatures. One way to do this is using the javah native tool which is a C stub generator that comes with the SDK. This tool is meant to create header files defining C-style functions for every native method found in the java code file. We shall use the following command:

javah Example1

After running this command, you should expect to see results such as these: let’s call the file Example1.h

   1. /* DO NOT EDIT THIS FILE - it is machine generated */   2. #include <jni.h>   3. /* Header for class Example1 */   4.    5. #ifndef _Included_Example1   6. #define _Included_Example1   7. #ifdef __cplusplus   8. extern "C" {   9. #endif  10.  11. JNIEXPORT jint JNICALL Java_Example1_intMethodName  12.   (JNIEnv *, jobject, jint);  13.  14. JNIEXPORT jboolean JNICALL Java_Example1_booleanMethodName  15.   (JNIEnv *, jobject, jboolean);  16.   17. JNIEXPORT jstring JNICALL Java_Example1_stringMethodName  18.  (JNIEnv *, jobject, jstring);  19.  20. JNIEXPORT jint JNICALL Java_Example1_intArrayMethodName  21.  (JNIEnv *, jobject, jintArray);  22.   23. #ifdef __cplusplus  24. }  25. #endif  26. #endif  

Writing the native code

In this section, we introduce the writing of C/C++. At this stage, the developer should note that all signatures must resemble the function declarations in Example1.h for the proper functioning of the program. Here are examples of implementations written in C and C++.

  1. #include "Example1.h"   2. #include <string.h>   3.    4. JNIEXPORT jint JNICALL Java_Example1_intMethodName   5.   (JNIEnv *env, jobject obj, jint num) {   6.    return num * num;   7. }   8.    9. JNIEXPORT jboolean JNICALL Java_Example1_booleanMethodName  10.   (JNIEnv *env, jobject obj, jboolean boolean) {  11.   return !boolean;  12. }  13.  14. JNIEXPORT jstring JNICALL Java_Example1_stringMethodName  15.   (JNIEnv *env, jobject obj, jstring string) {  16.     const char *str = (*env)->GetStringUTFChars(env, string, 0);  17.     char cap[128];  18.     strcpy(cap, str);  19.     (*env)->ReleaseStringUTFChars(env, string, str);  20.     return (*env)->NewStringUTF(env, strupr(cap));  21. }  22.   23. JNIEXPORT jint JNICALL Java_Example1_intArrayMethodNam  24.   (JNIEnv *env, jobject obj, jintArray array) {  25.     int i, sum = 0;  26.     jsize len = (*env)->GetArrayLength(env, array);  27.     jint *body = (*env)->GetIntArrayElements(env, array, 0);  28.     for (i=0; i<len; i++) 29. { sum += body[i]; 30. } 31. (*env)->ReleaseIntArrayElements(env, array, body, 0);  32.     return sum;  33. }  34.   35. void main(){}  

Creating a shared library

The native code is housed in the shared library. Most compilers can now create shared libraries. Commands differ from compiler to compiler, you will need to link in your headers from the JDK.

Running the java program

At this point, we ensure the code runs appropriately and performs the required task. Since all Java code executes in the Java virtual machine, we need the Java runtime environment. We can use the Java interpreter, java which is inbuilt in the SDK. The command is:

java Example1

Running the Example1.class program should display the following results:

PROMPT>java Example1  intMethodName: 25  booleanMethodName: false  stringMethodName: JAVA  intArrayMethodName: 33   PROMPT>  

Sources

https://en.wikipedia.org/wiki/Java_Native_Interface
https://developer.android.com/training/articles/perf-jni.html
http://carfield.com.hk/document/java/tutorial/jni_tutorial.pdf
https://www.ibm.com/developerworks/java/tutorials/j-jni/j-jni.html
https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
https://www.techrepublic.com/article/discover-how-the-java-native-interface-works/
https://www.protechtraining.com/content/java_fundamentals_tutorial-_java_native_interface_jni

Eclipse Java Tutorial

ONET IDC thành lập vào năm 2012, là công ty chuyên nghiệp tại Việt Nam trong lĩnh vực cung cấp dịch vụ Hosting, VPS, máy chủ vật lý, dịch vụ Firewall Anti DDoS, SSL… Với 10 năm xây dựng và phát triển, ứng dụng nhiều công nghệ hiện đại, ONET IDC đã giúp hàng ngàn khách hàng tin tưởng lựa chọn, mang lại sự ổn định tuyệt đối cho website của khách hàng để thúc đẩy việc kinh doanh đạt được hiệu quả và thành công.
Bài viết liên quan

Java 10 New Features

What’s New in Java 10 and What are the Future Plans? Recently Java has changed the pace of releases. Previously, it would...
28/12/2020

CentOS Install OpenJDK

When it’s necessary to build your apps or do some programming on Java, it’s always important to have all the necessary...
29/12/2020

JMap and JStack Tutorial

For any java delopers Jmap and Jstack are two important utility programs that can be used to debug issues, or understand...
28/12/2020
Bài Viết

Bài Viết Mới Cập Nhật

SỰ KHÁC BIỆT GIỮA RESIDENTIAL PROXY VÀ PROXY DATACENTER
17/02/2024

Mua Proxy v6 US Private chạy PRE, Face, Insta, Gmail
07/01/2024

Mua shadowsocks và hướng dẫn sữ dụng trên window
05/01/2024

Tại sao Proxy Socks lại được ưa chuộng hơn Proxy HTTP?
04/01/2024

Mua thuê proxy v4 nuôi zalo chất lượng cao, kinh nghiệm tránh quét tài khoản zalo
02/01/2024