Search code examples
java-native-interface

JNI method not invoked on centos7


I have a Java code ServiceTest.java that invokes JNI code buildCache() to build the cache. This codes compiled and exceuted correctly on Ubuntu; however, on centos I compiled and exceuted and got this error.

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.test.app.ServiceTest.buildCache()V
    at com.test.app.ServiceTest.buildCache(Native Method)
    at com.test.app.ServiceTest.<init>(ServiceTest.java:15)
    at com.test.app.ServiceTest.main(ServiceTest.java:47)

Looks like, it was able to load the so file, but it is not able to invoke the method.

ServiceTest.java

public class ServiceTest{


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

 public ServiceTest() {
        buildCache();
    }

 private native void buildCache();
}

libcacheService.so is placed in /usr/local/lib64. I have gcc 9 and jdk 1.8 and have set LD_LIBRARY_PATH=/usr/local/ and export $LD_LIBRARY_PATH.

Any idea on how to debug?


              ******Adding below simple testcode****** 

1.

public class Test{


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

    Test(){
    }

    public static void main(String...s){
      Test t = new Test();
      System.out.println(t.greetings());
    }
    private native String greetings();
}
  1. javah Test -> Test.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> /* Header for class Test */

#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Test
 * Method:    greetings
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_Test_greetings
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
  1. Greetings.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include "Test.h"
using namespace std;

class Test{

JNIEXPORT jstring JNICALL Java_Test_greetings(JNIEnv *env, jobject thisObject){
   jstring result = env->NewStringUTF("hi from JNI"); 
   return result;
 }  

};
  1. g++ --std=c++17 -g -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared -o greetings.so Greetings.cpp

  2. $JAVA_HOME/bin/java -Djava.library.path=/lib64 Test

  3. again same issue

Exception in thread "main" java.lang.UnsatisfiedLinkError: Test.greetings()Ljava/lang/String; at Test.greetings(Native Method) at Test.main(Test.java:13)

With same GCC 9 and jdk 1.8


Solution

  • Your Greetings.cpp should not include class Test:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <jni.h>
    #include "Test.h"
    using namespace std;
    
    JNIEXPORT jstring JNICALL Java_Test_greetings(JNIEnv *env, jobject thisObject){
       jstring result = env->NewStringUTF("hi from JNI"); 
       return result;
     }  
    
    

    Then, the Java statement System.loadLibrary("greet"); expects to find a libgreet.so in its java.library.path, so compile it as follows:

    g++ --std=c++17 -g -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared -o libgreet.so Greetings.cpp
    

    Next, verify that the symbol is named exactly like the function, ie nm libgreet.so | grep Java_Test_greetings should produce output like the following:

    0000000000000f20 T _Java_Test_greetings
    

    Finally, run your Java program with the correct java.library.path.