Wednesday, April 8, 2020

Invoking a C function from Java using JNI

This is our C function which we need to invoke from Java

hello.c
#include <stdio.h>

void sayHello() {
        printf("Hello world, from C\n");
}

Let's write the Java class which contains the native method to calls the C function

HelloWorld.java
public class HelloWorld {
    
    private native void callCHello();

    static {
        System.loadLibrary("chello");
    }

    public static void main(String[] args) {
        new HelloWorld().callCHello();
    }
    
}
Here we are loading the chello C library (we will be creating in the later part) which contains the implementation for the native method callCHello()

Compile the HelloWorld.java
javac HelloWorld.java

Create the native method header file
javah HelloWorld

This will generate HelloWorld.h file

Let's write the C code including the HelloWorld.h,  the function is named with the following convention.
Java_<Java class name>_<java native method name>

so here it will be:
Java_HelloWorld_callCHello

chello.c will call our original C function (sayHello()) which we needed to call from Java
chello.c
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"#include "hello.c"
JNIEXPORT void JNICALL Java_HelloWorld_callCHello(JNIEnv *env, jobject obj)  {
    sayHello();
    return;
}

Les's create the C library file to which we loaded in the Java code earlier with the following command

gcc chello.c -I $JAVA_HOME/include/ -I $JAVA_HOME/include/linux/ -shared -o libhello.so -fPIC

Please note that the so file name is libhello i.e with the "lib" prefix to the name we loaded in Java. Also I am including the linux related header files because I am working on linux. If it is windows it has to be changed as win32

let's run the HelloWorld java. We have to set the java.library.path to where the so file is located (in this case the current directory)
java HelloWorld

The output  will be "Hello World, from C"