Подтвердить что ты не робот

Как поймать исключение JNI/Java

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

  • Замените mypackage::Exception на свой собственный С++ Exception.
  • Если соответствующее исключение 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 за вклад в код С++.

Адаптировать исходный код, созданный 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/С++. Это может быть my-DLL-name.dll в Windows или my-DLL-name.so в GNU/Linux/Unix.

Действия

  • Создайте example.class из example.java (используя javac или maven или ваш любимый IDE Eclipse/Netbeans/IntelliJ IDEA/...)

  • Сгенерировать заголовочный файл C/С++ Java_my_group_mypackage_example.h из example.class с помощью javah