Search code examples
javac++cjava-native-interface

Java: Invoking native method giving "Exception in thread "main" java.lang.UnsatisfiedLinkError"


I am trying to call a simple native method in Java from C++, to achieve this I do the following:

  1. Create a simple class as shown below:

    public class HelloNative{
       public native void printString(String str);
       static{
            System.out.println("Current Directory is: " + System.getProperty("user.dir"));
            System.load(System.getProperty("user.dir") + "/libhellonative.so");
        }
        public static void main(String[] args){
            System.out.println("Calling Native Libraray (libhellonative.so) method printString");
            new HelloNative().printString("Message from Java to C");
         }
    }
    
  2. Create .h file for the native method using javah -jni which create the following declaration:

    JNIEXPORT void JNICALL Java_HelloNative_printString(JNIEnv *, jobject, jstring);

  3. Implement the native function in .cpp file as:

    JNIEXPORT void JNICALL Java_HelloNative_printString(JNIEnv* jni_env, jobject java_obj, jstring msg){
        printf("inside native method\n");
        jboolean iscopy;
        const char *message = (jni_env)->GetStringUTFChars( msg, &iscopy);
        printf("%s", message);
    }
    
  4. And finally create the .so file using:

    g++ HelloNative.cpp -o libhellonative.so -shared -Wl,-soname,libhellonative.so -static -lc -I /usr/lib/jvm/java-6-sun-1.6.0.26/include -I /usr/lib/jvm/java-6-sun-1.6.0.26/include/linux

But when I compile and run the .java file it's giving me Runtime Exception:

Current Directory is: /home/gmuhammad/Projects/test
Calling Native Libraray (libhellonative.so) method printString
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloNative.printString(Ljava/lang/String;)V
    at HelloNative.printString(Native Method)
    at HelloNative.main(HelloNative.java:16)

Solution

  • Ok, I got this to work. It has nothing to do with loading the library, but with actually calling the method from that library.

    I created .java, .h and .cpp files by copy/paste from your question and ran them (I had to add #include <jni.h> in the .cpp file) - and got exactly the same error as you did.

    Then I edited the .cpp file to include the generated .h file. Also, as maba indicated in his answer, you need to call (jni_env)->ReleaseStringUTFChars(msg, message); to release the object. My full .cpp file now looks like this:

    #include "HelloNative.h"
    
    JNIEXPORT void JNICALL Java_HelloNative_printString(JNIEnv* jni_env, jobject java_obj, jstring msg){
        printf("inside native method\n");
        jboolean iscopy;
        const char *message = (jni_env)->GetStringUTFChars( msg, &iscopy);
        printf("%s", message);
        (jni_env)->ReleaseStringUTFChars(msg, message);
    }
    

    I re-compiled the library, ran the java code - and voila! everything works. This way, it works regardless of which way you load the library, with load or loadLibrary.

    Give it a try.