如何捕获JNI / Javaexception
我的应用程序中有一个JNI图层。 在某些情况下,Java引发exception。 我怎么能在JNI层得到Javaexception? 我有这样的代码如下所示。
if((*(pConnDA->penv))->ExceptionCheck(pConnDA->penv)) { (*(pConnDA->penv))->ExceptionDescribe(pConnDA->penv); (*(pConnDA->penv))->ExceptionClear(pConnDA->penv); } 这段代码是否只能捕获JNIexception? 在控制台(stderr)中将exception描述logging在哪里? 我怎么把它放到缓冲区中,这样我就可以把它传递给我的logging器模块?
 如果您从 JNI调用Java方法,那么调用ExceptionCheck之后,如果Java抛出ExceptionCheck ,将返回JNI_TRUE 。 
 如果你只是调用一个JNI函数(比如FindClass ),那么ExceptionCheck会告诉你这个失败的方式是否会导致一个未决exception(就像FindClass会出错)。 
  ExceptionDescribe输出到stderr。 有没有方便的方法去其他任何地方,但ExceptionOccurred给你一个jthrowable如果你想玩它,或者你可以让它去Java和在那里处理它。 这是通常的风格: 
 jclass c = env->FindClass("class/does/not/Exist"); if (env->ExceptionCheck()) { return; } // otherwise do something with 'c'... 
请注意,返回的值不重要; 调用Java代码将永远不会看到它 – 它会看到未决的exception,而不是。
这是Elliott Hughes的答案的补充。 我的答案提供了一个循序渐进的例子,解释如何捕捉exception,以及如何使用JNI层在C ++和Java之间翻译它们。
简短的回答
看到正确的Elliott Hughes的答案 。
可重用的例子
这个答案和片段在公共领域或CC0中,以便于重用。 这里的所有源代码都是C ++ 03向后兼容的。
要重复使用上面的代码片段,请执行以下操作:
-  用你自己的C ++exceptionreplacemypackage::ExceptionException。
-  如果my.group.mypackage.Exception相应的Javaexceptionmy.group.mypackage.Exception,请将"my/group/mypackage/Exception"replace为"java/lang/RuntimeException"。
从Java捕获exception
另请参阅coliru上的片段 。
 void rethrow_cpp_exception_as_java_exception() { try { throw; // This allows to determine the type of the exception } catch (const mypackage::Exception& e) { jclass jc = env->FindClass("my/group/mypackage/Exception"); if(jc) env->ThrowNew (jc, e.what()); /* if null => NoClassDefFoundError already thrown */ } catch (const std::bad_alloc& e) { jclass jc = env->FindClass("java/lang/OutOfMemoryError"); if(jc) env->ThrowNew (jc, e.what()); } catch (const std::ios_base::failure& e) { jclass jc = env->FindClass("java/io/IOException"); if(jc) env->ThrowNew (jc, e.what()); } catch (const std::exception& e) { /* unknown exception (may derive from std::exception) */ jclass jc = env->FindClass("java/lang/Error"); if(jc) env->ThrowNew (jc, e.what()); } catch (...) { /* Oops I missed identifying this exception! */ jclass jc = env->FindClass("java/lang/Error"); if(jc) env->ThrowNew (jc, "Unidentified exception => " "Improve rethrow_cpp_exception_as_java_exception()" ); } } 
我感谢Mooing Duck对上述C ++代码的贡献。
适应JNI生成的源代码
 以下文件Java_my_group_mypackage_example.cpp使用上面的rethrow_cpp_exception_as_java_exception()函数: 
 JNIEXPORT jlong JNICALL Java_my_group_mypackage_example_function1 (JNIEnv *env, jobject object, jlong value) { try { /* ... my processing ... */ return jlong(result); } catch(...) { rethrow_cpp_exception_as_java_exception(); return 0; } } JNIEXPORT jstring JNICALL Java_my_group_mypackage_example_function2 (JNIEnv *env, jobject object, jlong value) { jstring jstr = 0 try { /* ... my processing ... */ jstr = env->NewStringUTF("my result"); } catch(...) { rethrow_cpp_exception_as_java_exception(); } return jstr; } JNIEXPORT void JNICALL Java_my_group_mypackage_example_function3 (JNIEnv *env, jobject object, jlong value) { try { /* ... my processing ... */ } catch(...) { rethrow_cpp_exception_as_java_exception(); } } 
对应的Java代码
 文件example.java 
 package my.group.mypackage; public class Example { static { System.loadLibrary("my-DLL-name"); } public Example() { /* ... */ } private native int function1(int); //declare DLL functions private native String function2(int); //using the keyword private native void function3(int); //'native' public void dosomething(int value) { int result = function1(value); String str = function2(value); //call your DLL functions function3(value); //as any other java function } } 
 注意:“ my-DLL-name ”是指从上面编译的C / C ++代码生成的dynamic库。 它可以是Windows上的my-DLL-name.dll或GNU / Linux / Unix上的my-DLL-name.so 。 
脚步
- 
从 example.java生成example.class(使用javac或maven或者您最喜欢的IDE Eclipse / Netbeans / IntelliJ IDEA / …)
- 
使用 javah从example.class生成C / C ++头文件Java_my_group_mypackage_example.h