我的应用程序中有一个JNI层。在某些情况下,Java会抛出异常。如何在JNI层中获取Java异常?我的代码如下所示。
if((*(pConnDA->penv))->ExceptionCheck(pConnDA->penv))
{
(*(pConnDA->penv))->ExceptionDescribe(pConnDA->penv);
(*(pConnDA->penv))->ExceptionClear(pConnDA->penv);
}
此代码块是否仅捕获JNI异常?将在控制台(stderr)中记录异常描述的位置?如何将其放入缓冲区,以便将其传递给记录器模块?
答案 0 :(得分:27)
如果从 JNI调用Java方法,则如果Java抛出异常,则之后调用ExceptionCheck
将返回JNI_TRUE
。
如果您只是调用JNI函数(例如FindClass
),ExceptionCheck
会告诉您这是否以某种方式失败,因为FindClass
将会执行在错误上。)
ExceptionDescribe
输出到stderr。没有方便的方法可以让它去任何其他地方,但ExceptionOccurred
给你一个jthrowable
如果你想玩它,或者你可以让它去Java并在那里处理它。这是通常的风格:
jclass c = env->FindClass("class/does/not/Exist");
if (env->ExceptionCheck()) {
return;
}
// otherwise do something with 'c'...
请注意,返回的价值无关紧要;调用Java代码永远不会看到它 - 它会看到挂起的异常。
答案 1 :(得分:14)
这是Elliott Hughes' answer的补充。我的回答提供了一个分步示例,说明如何捕获异常以及如何使用JNI层在C ++和Java单词之间进行转换。
查看正确的Elliott Hughes' answer。
这个答案和片段在公共领域或CC0中,以便于重复使用。这里的所有源代码都是C ++ 03向后兼容的。
要重复使用上述代码段,请执行以下操作:
mypackage::Exception
。 my.group.mypackage.Exception
,请将"my/group/mypackage/Exception"
替换为"java/lang/RuntimeException"
。另请参阅snippet on 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 ++代码的贡献。
以下文件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();
}
}
档案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 ++代码生成的动态库。它可以是Windows上的my-DLL-name.dll
或GNU / Linux / Unix上的my-DLL-name.so
。
从example.class
生成example.java
(使用javac
或maven或您喜欢的IDE Eclipse / Netbeans / IntelliJ IDEA /...)
使用Java_my_group_mypackage_example.h
example.class
生成C / C ++头文件javah
醇>