nativos - jni tutorial
Cómo atrapar Excepción JNI/Java (2)
Este es un complemento de la respuesta de Elliott Hughes . Mi respuesta proporciona un ejemplo paso a paso que explica cómo detectar excepciones y cómo traducirlas entre palabras C ++ y Java utilizando la capa JNI .
Respuesta corta
Vea la respuesta correcta de Elliott Hughes .
Ejemplo reutilizable
Esta respuesta y los fragmentos están en dominio público o en CC0 para facilitar la reutilización. Todo el código fuente aquí es C ++ 03 compatible con versiones anteriores.
Para reutilizar el fragmento anterior, haga lo siguiente:
- Reemplace
mypackage::Exception
por su propia excepción de C ++. - Si la excepción de Java correspondiente
my.group.mypackage.Exception
no está definida, entonces reemplace"my/group/mypackage/Exception"
por"java/lang/RuntimeException"
.
Captura excepciones de Java
Ver también el fragmento en 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()" );
}
}
Agradezco a Mooing Duck por su contribución al código C ++ anterior.
Adapte el código fuente generado por JNI
El siguiente archivo Java_my_group_mypackage_example.cpp
utiliza la función 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();
}
}
Código de Java correspondiente
Archivo 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
}
}
Nota: " my-DLL-name
" se refiere a la biblioteca dinámica producida a partir del código C / C ++ anterior compilado. Puede ser my-DLL-name.dll
en Windows o my-DLL-name.so
en GNU / Linux / Unix.
Pasos
Genera
example.class
desdeexample.java
(usandojavac
o maven o tu IDE favorito Eclipse / Netbeans / IntelliJ IDEA / ...)Genere el archivo de encabezado C / C ++
Java_my_group_mypackage_example.h
deexample.class
usandojavah
Tengo una capa JNI en mi aplicación. En algunos casos, Java arroja una excepción. ¿Cómo puedo obtener la excepción de Java en la capa JNI? Tengo el código algo así como lo siguiente.
if((*(pConnDA->penv))->ExceptionCheck(pConnDA->penv))
{
(*(pConnDA->penv))->ExceptionDescribe(pConnDA->penv);
(*(pConnDA->penv))->ExceptionClear(pConnDA->penv);
}
¿Este bloque de código atrapará solo las excepciones JNI? ¿Dónde se registrará la descripción de la excepción en la consola (stderr)? ¿Cómo puedo obtener esto en el búfer, para poder pasarlo a mi módulo logger?
si invoca un método Java desde JNI, al llamar a ExceptionCheck
posteriormente, se devolverá JNI_TRUE
si Java arrojó una excepción.
si solo está invocando una función JNI (como FindClass
), ExceptionCheck
le dirá si eso falló de una manera que deja una excepción pendiente (como FindClass
hará FindClass
por error).
ExceptionDescribe
salidas a stderr. no hay una manera conveniente de hacerlo funcionar en ningún otro lado, pero ExceptionOccurred
te ofrece un jthrowable
si quieres jugar con él, o puedes dejarlo subir a Java y manejarlo allí. ese es el estilo habitual:
jclass c = env->FindClass("class/does/not/Exist");
if (env->ExceptionCheck()) {
return;
}
// otherwise do something with ''c''...
tenga en cuenta que no importa qué valor devuelva; el código Java que lo llama nunca lo verá; en su lugar verá la excepción pendiente.