Search code examples
javac++java-native-interface

JNI java.lang.UnsatisfiedLinkError,cannot link method


I have seen a lot of questions of UnsatisfiedLinkError and I know what my problem is. I get

Exception in thread "main" java.lang.UnsatisfiedLinkError: Test.initCamera(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J

This means the dll has been loaded but it cannot find the method. However, I've checked my source code and java code. The method name and arguments are all right. I don't know what's wrong with my code.

Here are my codes.

Java:

public class Test {
public native long initCamera(String ip,String port,String username,String pwd); 
public native int snapPic(long id,String savePath,int no);
static{
    System.loadLibrary("dhconfigsdk");
    System.loadLibrary("dhnetsdk");
    System.loadLibrary("dhplay");
    System.loadLibrary("CameraCatcher");
}
public static void main(String[] args) {
    // TODO Auto-generated method stub
    Test tNative = new Test();
    String ip="192.108.1.108";
    String port="37777";
    String username="admin";
    String pwd="123456";
    long cameraId=tNative.initCamera(ip,port,username,pwd);
    System.out.println(cameraId);
    String savePath="D:/";
    int number=tNative.snapPic(cameraId,savePath,0);
}
}

C++:

JNIEXPORT jlong JNICALL Java_CameraCatcher_initCamera
(JNIEnv * env, jclass c, jstring arg_ip, jstring arg_port, jstring arg_username, jstring arg_pwd)
{
    ......
    return lLogin;
}


JNIEXPORT jint JNICALL Java_CameraCatcher_snapPic
(JNIEnv * env, jclass c, jlong arg_id, jstring arg_path, jint arg_no)
{
    .....
    return 12;
}

This really drives me crazy.

Update 1: Thanks for everyone's reply. I've changed my code just as @Mr Tarik showed.

Java:

public class CameraCatcher {
    static{
         System.loadLibrary("CameraCatcher");
    }
    public native long initCamera(String ip,String port,String username,String pwd);
    public native int snapPic(long id,String savePath,int no);
    public static void main(String[] args)
    {
        CameraCatcher tNative = new CameraCatcher();
        String ip="192.108.1.108";
        String port="37777";
        String username="admin";
        String pwd="123456";
        long cameraId=tNative.initCamera(ip,port,username,pwd);
        System.out.println(cameraId);
        String savePath="D:/project/j2ee/Example/result";
        int number=tNative.snapPic(cameraId,savePath,0);
    }
}

Then I use javah to generate header file:

#include <jni.h>

#ifndef _Included_CameraCatcher
#define _Included_CameraCatcher
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     CameraCatcher
 * Method:    initCamera
 * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_CameraCatcher_initCamera
  (JNIEnv *, jobject, jstring, jstring, jstring, jstring);

/*
 * Class:     CameraCatcher
 * Method:    snapPic
 * Signature: (JLjava/lang/String;I)I
 */
JNIEXPORT jint JNICALL Java_CameraCatcher_snapPic
  (JNIEnv *, jobject, jlong, jstring, jint);

#ifdef __cplusplus
}
#endif
#endif

C++ code:

JNIEXPORT jlong JNICALL Java_CameraCatcher_initCamera
(JNIEnv * env, jobject c, jstring arg_ip, jstring arg_port, jstring arg_username, jstring arg_pwd)
{
    return 1;
}
JNIEXPORT jint JNICALL Java_CameraCatcher_snapPic
(JNIEnv * env, jobject c, jlong arg_id, jstring arg_path, jint arg_no)
{
    return 2;
}

I compile this code and get new dll. However it still has the error as before.......

Update 2: Yes.It works. I don't know why the function definition code changed in my .cpp file. I just changed the jclass to jobject as EJP told me the problem yesterday.Maybe it has been changed since yesterday by chance and I didn't observe. It's all my carelessness. Thanks for everyone again.

The problem is exactly what EJP said. I generated the file with static function but make it work in a non-static way. Another problem is that I generated the class CameraCatcher while I used the class Test.


Solution

  • I tested your code. you need to edit functions names in c++ you need to have something like this

        #include "test.h"
        #include <jni.h>
    
    JNIEXPORT jlong JNICALL Java_CameraCatcher_Test_initCamera
      (JNIEnv *env, jobject  obj, jstring ip, jstring port, jstring username, jstring pwd){
    
        return 1.0;
    }
    JNIEXPORT jint JNICALL Java_CameraCatcher_Test_snapPic
      (JNIEnv *env, jobject obj, jlong id, jstring savePath, jint no){
        return 5;
    }
    

    dont forget the name of your class Test to add it in Java_CameraCatcher_Test_snapPic.

    edit 1: this is what i have in header:

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class CameraCatcher */
    
    #ifndef _Included_CameraCatcher
    #define _Included_CameraCatcher
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     CameraCatcher
     * Method:    initCamera
     * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J
     */
    JNIEXPORT jlong JNICALL Java_CameraCatcher_initCamera
      (JNIEnv *, jobject, jstring, jstring, jstring, jstring);
    
    /*
     * Class:     CameraCatcher
     * Method:    snapPic
     * Signature: (JLjava/lang/String;I)I
     */
    JNIEXPORT jint JNICALL Java_CameraCatcher_snapPic
      (JNIEnv *, jobject, jlong, jstring, jint);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    c++:

    #include "cameracatcher.h"
    #include <jni.h>
    #include <stdio.h>
    #include <iostream>
    #include <unistd.h>
    JNIEXPORT jlong JNICALL Java_CameraCatcher_initCamera
      (JNIEnv *env, jobject  obj, jstring ip, jstring port, jstring username, jstring pwd){
    
        return 1.0;
    }
    JNIEXPORT jint JNICALL Java_CameraCatcher_snapPic
      (JNIEnv *env, jobject obj, jlong id, jstring savePath, jint no){
        return 5.5;
    }
    

    Java:

    public class CameraCatcher {
    
        public native long initCamera(String ip, String port, String username, String pwd);
    
        public native int snapPic(long id, String savePath, int no);
    
        static {
            System.load("/home/tarik/NetBeansProjects/Testc++/dist/test.so");
        }
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            CameraCatcher tNative = new CameraCatcher();
            String ip = "192.108.1.108";
            String port = "37777";
            String username = "admin";
            String pwd = "123456";
            long cameraId = tNative.initCamera(ip, port, username, pwd);
            System.out.println(cameraId);
            String savePath = "D:/";
            int number = tNative.snapPic(cameraId, savePath, 0);
            System.out.println(number);
        }
    }
    

    All works fine.