如何捕获JNI / Java异常

时间:2010-01-13 05:14:54

标签: java-native-interface

我的应用程序中有一个JNI层。在某些情况下,Java会抛出异常。如何在JNI层中获取Java异常?我的代码如下所示。

if((*(pConnDA->penv))->ExceptionCheck(pConnDA->penv))
{
    (*(pConnDA->penv))->ExceptionDescribe(pConnDA->penv); 
    (*(pConnDA->penv))->ExceptionClear(pConnDA->penv);
}

此代码块是否仅捕获JNI异常?将在控制台(stderr)中记录异常描述的位置?如何将其放入缓冲区,以便将其传递给记录器模块?

2 个答案:

答案 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向后兼容的。

要重复使用上述代码段,请执行以下操作:

  • 用您自己的C ++异常替换mypackage::Exception
  • 如果未定义相应的Java异常my.group.mypackage.Exception,请将"my/group/mypackage/Exception"替换为"java/lang/RuntimeException"

从Java中捕获异常

另请参阅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 ++代码的贡献。

调整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 ++代码生成的动态库。它可以是Windows上的my-DLL-name.dll或GNU / Linux / Unix上的my-DLL-name.so

步骤

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

  2. 使用Java_my_group_mypackage_example.h

  3. example.class生成C / C ++头文件javah