Как поймать исключение JNI/Java
В моем приложении есть слой JNI. В некоторых случаях Java генерирует исключение. Как я могу получить исключение Java в слое JNI? У меня есть код, похожий на следующий.
if((*(pConnDA->penv))->ExceptionCheck(pConnDA->penv))
{
(*(pConnDA->penv))->ExceptionDescribe(pConnDA->penv);
(*(pConnDA->penv))->ExceptionClear(pConnDA->penv);
}
Будет ли этот блок кода захватывать только исключения JNI? Где будет записываться описание исключения в консоли (stderr)? Как это сделать в буфере, чтобы я мог передать его в мой модуль журнала?
Ответы
Ответ 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