使用JNI时如何在C ++中获取Javaexception的描述?

我想确定使用JNI从C ++代码调用该函数时Java函数抛出了什么exception。 我有以下代码捕获Javaexception:

JNIEnv * pEnv; // assume this is properly initialized jclass javaClass; // ditto jmethodID javaFunction; // ditto pEnv->CallStaticVoidMethod(javaClass, javaFunction); jthrowable exc; if(exc = pEnv->ExceptionOccurred()) { pEnv->ExceptionClear(); } 

我不知道如何在此C ++代码中获取有关Javaexception的描述性信息。 有人可以帮忙吗?

我在每次JNI调用后都省略了调用ExceptionCheck() ,并检查了为简洁起见找到方法的任何失败尝试:你应该在实现时添加它们。

首先,存储exception,然后获取获取有关Throwable信息所需的Java方法:

 // Get the exception and clear as no // JNI calls can be made while an exception exists. jthrowable exception = pEnv->ExceptionOccurred(); pEnv->ExceptionClear(); jclass throwable_class = pEnv->FindClass("java/lang/Throwable"); jmethodID mid_throwable_getCause = pEnv->GetMethodID(throwable_class, "getCause", "()Ljava/lang/Throwable;"); jmethodID mid_throwable_getStackTrace = pEnv->GetMethodID(throwable_class, "getStackTrace", "()[Ljava/lang/StackTraceElement;"); jmethodID mid_throwable_toString = pEnv->GetMethodID(throwable_class, "toString", "()Ljava/lang/String;"); jclass frame_class = pEnv->FindClass("java/lang/StackTraceElement"); jmethodID mid_frame_toString = pEnv->GetMethodID(frame_class, "toString", "()Ljava/lang/String;"); 

其次,递归构造错误消息(您可能想要修改它):

 std::string error_msg; // Could use ostringstream instead. _append_exception_trace_messages(*pEnv, error_msg, exception, mid_throwable_getCause, mid_throwable_getStackTrace, mid_throwable_toString, mid_frame_toString); void _append_exception_trace_messages( JNIEnv& a_jni_env, std::string& a_error_msg, jthrowable a_exception, jmethodID a_mid_throwable_getCause, jmethodID a_mid_throwable_getStackTrace, jmethodID a_mid_throwable_toString, jmethodID a_mid_frame_toString) { // Get the array of StackTraceElements. jobjectArray frames = (jobjectArray) a_jni_env.CallObjectMethod( a_exception, a_mid_throwable_getStackTrace); jsize frames_length = a_jni_env.GetArrayLength(frames); // Add Throwable.toString() before descending // stack trace messages. if (0 != frames) { jstring msg_obj = (jstring) a_jni_env.CallObjectMethod(a_exception, a_mid_throwable_toString); const char* msg_str = a_jni_env.GetStringUTFChars(msg_obj, 0); // If this is not the top-of-the-trace then // this is a cause. if (!a_error_msg.empty()) { a_error_msg += "\nCaused by: "; a_error_msg += msg_str; } else { a_error_msg = msg_str; } a_jni_env.ReleaseStringUTFChars(msg_obj, msg_str); a_jni_env.DeleteLocalRef(msg_obj); } // Append stack trace messages if there are any. if (frames_length > 0) { jsize i = 0; for (i = 0; i < frames_length; i++) { // Get the string returned from the 'toString()' // method of the next frame and append it to // the error message. jobject frame = a_jni_env.GetObjectArrayElement(frames, i); jstring msg_obj = (jstring) a_jni_env.CallObjectMethod(frame, a_mid_frame_toString); const char* msg_str = a_jni_env.GetStringUTFChars(msg_obj, 0); a_error_msg += "\n "; a_error_msg += msg_str; a_jni_env.ReleaseStringUTFChars(msg_obj, msg_str); a_jni_env.DeleteLocalRef(msg_obj); a_jni_env.DeleteLocalRef(frame); } } // If 'a_exception' has a cause then append the // stack trace messages from the cause. if (0 != frames) { jthrowable cause = (jthrowable) a_jni_env.CallObjectMethod( a_exception, a_mid_throwable_getCause); if (0 != cause) { _append_exception_trace_messages(a_jni_env, a_error_msg, cause, a_mid_throwable_getCause, a_mid_throwable_getStackTrace, a_mid_throwable_toString, a_mid_frame_toString); } } } 

我从几年前编写的代码中复制了这个(修改后用于消除锅炉板ExceptionCheck() s),但我没有编译我发布的内容,但一般的方法有希望清楚。

如果您只对exception的堆栈跟踪感兴趣,您可以:

 if (env->ExceptionOccurred()) // check if an exception occurred { env->ExceptionDescribe(); // print the stack trace } 

解决这个问题的简单方法是声明JNI方法抛出所有可能的exception,然后:

 jthrowable throwable = ExceptionOccurred(env); if (throwable != NULL) Throw(env, throwable); 

并让你的Java代码处理它。