DEV Community

Marcos Gabriel de Oliveira Favaretto
Marcos Gabriel de Oliveira Favaretto

Posted on • Edited on

Calling C native code from Java using JNI

Hello community!
This is my first post, hope you like it! Notice that all content here is about my studies on JNI. Feel free to make suggestions, corrections, etc. :D

Good read!^^

NATIVE CALL FROM JAVA CODE TO C CODE.

The keyword "native" on Java allow us to call native libraries, by using the JNI.

That document was based on Baeldung post, Prof. Gustavo Leitão video and Oracle documentation about JNI.

1. Introduction

The JNI (Java Native Interface) allows Java to access codes on C and C++.

Commonly used for specifics performance cases, to handle hardwares or even use an existing library (not to need to rewrite).

2. The "native" key word.

When we are working with JNI, the native key word need to be used.

That key word says for JVM: "That method has an implementation on other language".

Here is an example of a native method:

public native void myNativeMethod();
Enter fullscreen mode Exit fullscreen mode

Native methods are like abstracts one, with the difference that its implementation will be done in a separated native code file instead of a .java one.

3. The "System.loadLibrary()" method.

In order for the JVM to use the native code, it is necessary to use the static method System.loadLibrary(String libName). That one will load the provided library from the file system into our memory.

Here is a call example:

System.loadLibrary(mylibrary);
Enter fullscreen mode Exit fullscreen mode

It is very important to say that the library's name provided as parameter needs to follow some rules, depending on the platform that the JVM is being executed. For example, lets suppose a library called as "taxcalculator". The following table shows which names should be used for that example.

System Name Parameter Value Name of File (without blank spaces)
Windows taxcalculator taxcalculator .dll
Solaris taxcalculator libtaxcalculator .so

The provided parameter is converted automatically by JVM like as showed from column "Parameter Value" to "Name File".

Alternatively, we can use the command System.load(D:\\my\\library\\path\\libmylibrary.dll) to find a library by its fully path.

4. Step by step.

After a simple introduction, let's make a simple example by creating a calculator in Java but making all calculations on C.

4.1. Creating a Java program.

The first step is to create our Java class and declare its methods to be implemented on another language. As said before, we need to load our library, by using the method System.loadLibrary(mylibrary).

image

Note that, the native methods does not have implementations here since it will be done at a C file later. After compile this Java class, there are no errors.

MainClassCompileResult

4.2. Generating C header.

Java's compiler allows us to generete our C header automatically, using the command below:

javac Calculator.java -h ../c/
Enter fullscreen mode Exit fullscreen mode

Where:

javac: Executes the Java compiler.

Calculator.java: Is the class that needs to be implemented in C.

-h: Says for compiler where to save the native header file.

../c/: Is the path where the header is going to be saved.

NOTE: If you are running a version before 10, use the javah instead of javac -h <path>

After execute that command, a new .h is generated. There, we can see all method's signature that we defined as native using the "native" key word.

headerGenerated

4.3. Implementing the methods with native code.

After all these steps, now we need to create the implementation of C code to the Java declared methods.

Let's create a new .c file, there, we included the generated header file and implement a function for all methods, following its signature.

CalculatorInC

Notice that the methods signature was copy from the generated header, with the difference that all parameters have been changed to have a name that can be referenced in the code.

4.4. Compiling C class.

For compile the C class, I will use the GCC. If you are using Windows (like me), use that step-by-step for stalling it. If you are using Linux, you must already have it installed.

To compile it, we can use the following command (you will have to change it for your case).

gcc -o libcalculator.dll -shared -I"your\java\home\include" -I"your\java\home\include\win32" -I"your\project\c" ./Calculator.c;
Enter fullscreen mode Exit fullscreen mode

Where:

gcc: Executes the GNU Compiler C.

-o: Says for compiler where to save the generated file.

libcalculator.dll: Is the name of the generated file.

-shared: Says for compiler to create a shared library.

-I"your\java\home\include": Is the location of jni.h, that is used by Calculator.h.

-I"your\java\home\include\win32": Is the location of jni_md.h for Windows, that is also used by Calculator.h.

-I"your\project\c": Is the location of Calculator.h, that is used by Calculator.c.

./Calculator.c: This is the file we want to compile

All that code needs to be executed in one line. After it, a libcalculator.dll will be generated.

LibGenerated

4.5. Executing our program.

After all these steps, we are able to execute our program. Just do it by using the following command on your/project/java:

java -Djava.library.path=location/of/libcalculattor Calculator 2 2
Enter fullscreen mode Exit fullscreen mode

NOTE: If you used the System.load instead of System.loadLibrary, the -Djava.library.path=location/of/libcalculattor argument does not need to be provided.

The following image shows the application working:

Result

This is a basic example of how to use JNI. You can see the code by clicking here.

Top comments (0)