在我的情况下使用 JNI 调用 CallVoidMethod 时抛出 NPE 的可能原因是什么
What's the possible reason why NPE is throwed when call CallVoidMethod with JNI in my situation
场景:
我已经用 Cpp 构建了一个 DLL,它被一个 java 应用程序和 JNI 使用。 DLL 也会调用 Java 中的方法。但是,当我调用 CallVoidMethod 时,java.lang.NullPointerException 将打印在 java 控制台中。
代码如下:
void CaptureCallback::ACallbackMethod(){
jvm->AttachCurrentThread((void **)&env, NULL);
jmethodID mid= env->GetMethodID(cls, "helloWorld", "()V");
cout << "The jmethodID is : " << mid << endl;
cout << "The jobject is : " << jobj << endl;
cout << "The env is: " << env << endl;
env->CallVoidMethod(obj, mid );
jvm->DetachCurrentThread();
}
到目前为止我尝试过的:
- jmethod 的值不是零。说明我找到了Java这边的方法。(如有错误请指正。)
- 两个jclass cls = env->GetObjectClass(jobj);和 jclass cls = env->FindClass(absolute_path) 试图获取 jclass 信息。
stacktrace 非常简单,它是:
线程异常 "Thread-2"
java.lang.NullPointerException
所以我很难找到原因。
当前进度:
当我将 ACallbackMethod 的主体放入 Constructor 方法时,我设法调用了 helloWorld 方法。构造函数方法如下所示:
CaptureCallback::CaptureCallback(JNIEnv *p_env, jobject p_jobj){
env = p_env;
jobj = p_jobj;
jvm->AttachCurrentThread((void **)&env, NULL);
jmethodID mid= env->GetMethodID(cls, "helloWorld", "()V");
cout << "The jmethodID is : " << mid << endl;
cout << "The jobject is : " << obj << endl;
cout << "The env is: " << env << endl;
env->CallVoidMethod(obj, mid );
jvm->DetachCurrentThread();
}
CaptureCallback 是一个 class,它继承自 IDL 生成的头文件,CaptureCallback::ACallbackMethod 保持从本机调用 side.The 未声明的变量,如 env、jobj 等已声明在 CaptureCallback.h 个文件中。
与您上次提问的答案相同。 obj
为 null,或者在被调用方法或它调用的方法中为 null 时取消引用某些内容,等等递归。或者,某人(可能是您提供了一些现在已删除的代码)出于某些可能无关的原因故意抛出此异常。
[反对者请注意:这些确实是唯一可能的原因。如果您不同意,请给出您选择的理由。]
你的代码很遗憾没有错误检查。您需要检查每个 JNI 调用的结果,而不仅仅是您喜欢的那些。之前的任何一个都可能抛出 NPE。我在上面依赖你断言它是 CallVoidMethod()
,但它可能不是。
为什么要将可能是任何东西的异常变成 NullPointerException
是个谜。您应该重新抛出 throwable
,而不是抛出一个新的、可能不相关的异常来混淆自己。
场景: 我已经用 Cpp 构建了一个 DLL,它被一个 java 应用程序和 JNI 使用。 DLL 也会调用 Java 中的方法。但是,当我调用 CallVoidMethod 时,java.lang.NullPointerException 将打印在 java 控制台中。
代码如下:
void CaptureCallback::ACallbackMethod(){
jvm->AttachCurrentThread((void **)&env, NULL);
jmethodID mid= env->GetMethodID(cls, "helloWorld", "()V");
cout << "The jmethodID is : " << mid << endl;
cout << "The jobject is : " << jobj << endl;
cout << "The env is: " << env << endl;
env->CallVoidMethod(obj, mid );
jvm->DetachCurrentThread();
}
到目前为止我尝试过的:
- jmethod 的值不是零。说明我找到了Java这边的方法。(如有错误请指正。)
- 两个jclass cls = env->GetObjectClass(jobj);和 jclass cls = env->FindClass(absolute_path) 试图获取 jclass 信息。
stacktrace 非常简单,它是:
线程异常 "Thread-2"
java.lang.NullPointerException
所以我很难找到原因。
当前进度: 当我将 ACallbackMethod 的主体放入 Constructor 方法时,我设法调用了 helloWorld 方法。构造函数方法如下所示:
CaptureCallback::CaptureCallback(JNIEnv *p_env, jobject p_jobj){
env = p_env;
jobj = p_jobj;
jvm->AttachCurrentThread((void **)&env, NULL);
jmethodID mid= env->GetMethodID(cls, "helloWorld", "()V");
cout << "The jmethodID is : " << mid << endl;
cout << "The jobject is : " << obj << endl;
cout << "The env is: " << env << endl;
env->CallVoidMethod(obj, mid );
jvm->DetachCurrentThread();
}
CaptureCallback 是一个 class,它继承自 IDL 生成的头文件,CaptureCallback::ACallbackMethod 保持从本机调用 side.The 未声明的变量,如 env、jobj 等已声明在 CaptureCallback.h 个文件中。
与您上次提问的答案相同。 obj
为 null,或者在被调用方法或它调用的方法中为 null 时取消引用某些内容,等等递归。或者,某人(可能是您提供了一些现在已删除的代码)出于某些可能无关的原因故意抛出此异常。
[反对者请注意:这些确实是唯一可能的原因。如果您不同意,请给出您选择的理由。]
你的代码很遗憾没有错误检查。您需要检查每个 JNI 调用的结果,而不仅仅是您喜欢的那些。之前的任何一个都可能抛出 NPE。我在上面依赖你断言它是 CallVoidMethod()
,但它可能不是。
为什么要将可能是任何东西的异常变成 NullPointerException
是个谜。您应该重新抛出 throwable
,而不是抛出一个新的、可能不相关的异常来混淆自己。