我想确定使用JNI从C ++代码调用该函数时Java函数引发了什么异常。我有以下捕获Java异常的代码:
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 ++代码中获取有关Java异常的描述性信息。有人可以帮忙吗?
ExceptionCheck()在每次JNI 调用之后,我都省略了调用,并没有检查任何为简便起见而定位失败的尝试:在实现时应添加这些方法。
ExceptionCheck()
首先,存储异常,然后获取获取有关的信息所必需的Java方法Throwable:
Throwable
// 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(),但是我没有编译我发布的内容,但是希望通用的方法是明确的。