JavaData & JavaGetting Started with JNI

Getting Started with JNI

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Java programs are compiled to byte code like a half chewed cud ruminated further by the Java run-time environment to bring-forth the actual result of the code. Because Java programs run under the sanctum of JVM, applications written in Java are regarded as “good boys” of the programming world. Any malicious activity of system manipulation is restrained within the periphery of JVM. JNI spoils the kid with a beckon to mingle freely with native code written in some of the vicious languages, such as C, C++, and so forth. Jests apart, JNI (Java Native Interface) is a programming interface through which Java byte code can interact with any native code. The write-up delves into the domain and explicates the concept with some key details.

JNI Method Overview

JVM makes no difference between a native method and a Java method call. That does not make it congruous to the Java method. The main differences between a Java method and native methods are:

  • The native methods are written in a language other than Java and the implementation of such methods does not use JVM instructions.
  • Native methods are compiled into a shared library. JVM loads this shared library and exposes the method to Java code so that it can be handled in a manner similar to a pure Java method.
  • Once native methods are compiled into platform-specific machine code, they usually use a stack called “C Stack”‘ provided by JVM to trace their state. “C Stack” is a legacy name retained; it used to be the usual way of implementing native methods in C and compiling into native codes.

JNI Pros and Cons

A Java programmer can take advantage of the native language features that may not be possible in Java entirely.

  • Sometimes, a certain Java module may have better performance if implemented in, say, C/C++. In such a situation, Java can take advantage of the JNI to work in unison with native languages.
  • Sometimes, some standard implementation is done in a language other than Java and a Java program wants to take advantage of that legacy code and use it along with Java modules in an application.
  • In a way, we can say that JNI can bring extra zing to our application. This, however, is arguable if it is in regard to performance speedup, because there is an equally solid reason in favor of Java that, for performance tuning, we do not need native language support. A simple fine tuning of the Java code itself would boost the performance. This may or may not be true, but there are certain situations where JNI can definitely be a welcome inclusion. For example,
    • As we know, searching and sorting can be quite resource intensive. If it is implemented in a low-level code on a huge collection of data, Java would be no match on the basis of performance.
    • Graphics programming is very processor intensive and has a bad reputation of bogging down performance. Java running on a layer of virtual environment can be a sloth in comparison to pure number crunching capability of the native code.
    • Another situation: Suppose we cannot rely on the Java garbage collection for reclaiming unused memory and want to take up the cleansing work ourselves. From another perspective, we want to limit the number of objects created and release them as soon as they are not needed, without waiting for the garbage collector to act on our plea.

These types of situations do not occur very often; otherwise, we can always take the help of JNI. JNI provides the standard native interface to collaborate other languages with Java. But, this flexibility has a price to pay.

  • The main disadvantage of JNI is that, when a Java program uses native languages it compromises portability, one of its core feature, in the same sense as it is renowned for “compile once, run everywhere.” Java code is compiled into a platform-independent format called byte-code. This byte-code follows JVM instruction and runs within the periphery of the Java run-time environment. Java code, once compiled, can run on any platform without the slightest changes or any need of recompilation. Native code, on the other hand, is hard compiled into a platform-dependent format. The only way out is to compile the native source code according to various platforms and package it with Java, so that when the application runs, it can use the specific library in accordance to the platform it is running.
  • Complexity creeps into Java as soon as JNI steps in. Once native code is included, the development environment and deployment procedure become complicated. To what extent this overhead is acceptable depends on the discretion of the programmer because one must be cautious to use JNI only when it is an absolute necessity.

A Simple JNI Application

When writing a JNI application for the first time, the main hurdle one will face is that of the overwhelming steps involved in compiling the code. Following is a very rudimentary application; the highlight is not on the code but on the steps involved. If you can compile and run the application, you have crossed a major hurdle. The rest that remains is grasping the concepts involved, which we’ll focus on in the next set of articles. Stay tuned.

The steps shown herein are the simplest way to write a JNI app disregarding standard/good programming technique. Make sure you have a GNU g++ compiler installed for C/C++, along with latest JDK. Also, make sure you can compile C/C++ source code from a command line/terminal, along with Java. This can be accomplished by setting up bin folder for both Java and C/C++ compiler in the PATH environment variable.

1. Write the Java Code

To keep it simple, create a folder and name it, say, JNI_project. We shall use it as a parent folder for every file we create. Now, create a Java file with the following code:

public class JNITest {
   static{
      System.load("/home/user1/
         JNI_project/mynativelib.so");
      //System.load("C:JNI_project
      //mynativelib.dll");
   }
   public native void greet();
   public static void main(String[] args) {
      JNITest test=new JNITest();
      test.greet();
   }
}

2. Compile the Java Code

Compiling a Java program that uses JNI is the same as compiling a normal Java code. This will create a JNITest.class file:

javac JNITest.java

3. Create the C/C++ Header File

The C/C++ header file can be created with the javah tool provided with the JDK. It is automatically created by the tool. Make sure not to change anything in this header file:

javah JNITest

Or, you can give the package a name with classpath:

javah -cp C:JNI_project <your package name>.JNITest.java

The generated header file is as follows:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNITest */
#ifndef _Included_JNITest
#define _Included_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JNITest
 * Method:    greet
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNITest_greet (JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

4. Write the C/C++ Program

This is a simple C/C++ code. The header file jni.h is located in the include directory of JDK. Create the C/C++ file with the name jnitest.cpp:

#include<stdio.h>
#include<jni.h>
#include "JNITest.h"
JNIEXPORT void JNICALL Java_JNITest_greet
   (JNIEnv *env, jobject obj){
      printf("n...Welcome to the world of JNI...n");
      return;
}

5. Create a Shared Library

Now, to compile the C/C++ code and create shared libraries, do as follows:

For Windows:

C:> g++ -Wl,--kill-at -shared -IC:/JDK/include
   -IC:/JDK/include/win32 -IC:/dll
   -o C:/JNI_project/mynativelib.dll
   C:/JNI_project/jnitest.cpp

For Linux:

$ g++ -fPIC -shared
   -I/usr/lib/jvm/java-8-oracle/include
   -I/usr/lib/jvm/java-8-oracle/include/linux
   -I/home/user1/JNI_project/
   -o /home/user1/JNI_project/mynativelib.so
   /home/user1/JNI_project/jnitest.cpp

6. Run the JNI Empowered Java Code

Now, to run the application, type the following command from the command line/terminal:

Windows command line:

java -Djava.library.path=C:JNI_project JNITest

Linux terminal:

java -Djava.library.path=/home/user1/
   JNI_project JNITest

That’s it. The application now should greet with a welcome message.

Conclusion

With JNI, Java kept one window open to interact with the world outside its own genre. This is a very powerful feature and can be used or misused in programming low-level platform interaction that is beyond Java. In common application development, JNI is rarely a required feature. But, for embedded application development, JNI can be a necessary extension. We can do almost anything when we conjoin Java with a programming language such as C/C++. So, JNI-empowered Java gives us more of a reason to rejoice than to be critical of its drawbacks.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories