Как поймать исключение JNI / Java - PullRequest
26 голосов
/ 13 января 2010

В моем приложении есть слой JNI. В некоторых случаях Java выдает исключение. Как я могу получить исключение Java в слое JNI? У меня есть код что-то вроде следующего.

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

Будет ли этот блок кода перехватывать только исключения JNI? Где будет регистрироваться описание исключения в консоли (stderr)? Как мне поместить это в буфер, чтобы я мог передать его в свой модуль логгера?

Ответы [ 2 ]

27 голосов
/ 24 января 2010

если вы вызываете Java-метод из JNI, вызов ExceptionCheck впоследствии вернет JNI_TRUE, если Java сгенерировала исключение.

если вы просто вызываете функцию 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 никогда его не увидит - вместо этого он увидит ожидающее исключение.

14 голосов
/ 08 марта 2013

Это дополнение к ответу Эллиотта Хьюза . В моем ответе приведен пошаговый пример, объясняющий, как перехватывать исключения и как их переводить между словами C ++ и Java, используя слой JNI .

Краткий ответ

См. Правильный ответ Эллиота Хьюза .

Пример многократного использования

Этот ответ и фрагменты находятся в свободном доступе или в CC0 для упрощения повторного использования. Весь исходный код здесь обратно совместим с C ++ 03.

Чтобы использовать приведенный выше фрагмент, выполните следующие действия:

  • Замените mypackage::Exception вашим собственным исключением C ++.
  • Если соответствующее исключение Java my.group.mypackage.Exception не определено, то замените "my/group/mypackage/Exception" на "java/lang/RuntimeException".

Перехват исключений из Java

См. Также фрагмент на 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 ++. Это может быть my-DLL-name.dll в Windows или my-DLL-name.so в GNU / Linux / Unix.

Steps

  1. Генерация example.class из example.java (используя javac или maven или ваш любимый IDE Eclipse / Netbeans / IntelliJ IDEA /...)

  2. Создание заголовочного файла C / C ++ Java_my_group_mypackage_example.h из example.class с использованием javah

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...