如何捕获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::Exception Exception。
  • 如果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

脚步

  1. example.java生成example.class (使用javac或maven或者您最喜欢的IDE Eclipse / Netbeans / IntelliJ IDEA / …)

  2. 使用javahexample.class生成C / C ++头文件Java_my_group_mypackage_example.h