Search code examples
javac++java-native-interface

UnsatisfiedLinkError for a basic native method


I have those two super basic methods in Java like so:

package com.lisek;

class HelloWorldJNI {

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

    public static void main(String[] args) {
        HelloWorldJNI helloWorldJNI = new HelloWorldJNI();
        helloWorldJNI.sayHello();
        helloWorldJNI.sayHello2();
    }

    // Declare a native method sayHello() that receives no arguments and returns void
    private native void sayHello();
    private native void sayHello2();
}

I am generating JNI files like so javac -h . HelloWorldJNI.java which results in such com_lisek_HelloWorldJNI.h file:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lisek_HelloWorldJNI */

#ifndef _Included_com_lisek_HelloWorldJNI
#define _Included_com_lisek_HelloWorldJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_lisek_HelloWorldJNI
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_lisek_HelloWorldJNI_sayHello
  (JNIEnv *, jobject);

/*
 * Class:     com_lisek_HelloWorldJNI
 * Method:    sayHello2
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_lisek_HelloWorldJNI_sayHello2
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

And I am doing implementation of those in the same exact manner in the com_lisek_HelloWorldJNI.cpp file like so:

#include "com_lisek_HelloWorldJNI.h"
#include <stdio.h>
#include <iostream>
#include <jni.h>

JNIEXPORT void JNICALL Java_com_lisek_HelloWorldJNI_sayHello (JNIEnv* env, jobject thisObject) {
   std::cout << "Hello from C++ !!" << std::endl;
}

JNIEXPORT void JNICALL Java_com_lisek_HelloWorldJNI_sayHello2 (JNIEnv* env, jobject thisObject) {
    std::cout << "Hello from C++ !!" << std::endl;
}

I am compiling the code with g++ -c -I"C:\Program Files\Java\jdk1.8.0_181\include" -I"C:\Program Files\Java\jdk1.8.0_181\include\win32" com_lisek_HelloWorldJNI.cpp -o com_lisek_HelloWorldJNI.o and generating .dll with g++ -shared -o native.dll com_lisek_HelloWorldJNI.o -Wl,--add-stdcall-alias. All looks very well to me and I can not spot any flaw of this code but nevertheless in Java while running the code I am getting exception only on the second method:

Hello from C++ !!
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.lisek.HelloWorldJNI.sayHello2()V
    at com.lisek.HelloWorldJNI.sayHello2(Native Method)
    at com.lisek.HelloWorldJNI.main(HelloWorldJNI.java:12)

It means to me that the .dll is loaded properly as if I do two calls of the sayHello() I will get the Hello twice. Seriously, what is going on?


Solution

  • Remember to compile and run your code with -Djava.library.path flag set like so:

    java -cp . -Djava.library.path="D:\\Workspace\\JNI\\Callback\\src\\com\\lisek" com.lisek.HelloWorldJNI

    But it still dazzles me that it was able to run the first sayHello() but was not able to run sayHello2(). Can't think of any reasonable idea why this happens.