usuario210444
Tengo una capa JNI en mi aplicación. En algunos casos, Java lanza una excepción. ¿Cómo puedo obtener la excepción de Java en la capa JNI? Tengo el código algo como lo siguiente.
if((*(pConnDA->penv))->ExceptionCheck(pConnDA->penv))
{
(*(pConnDA->penv))->ExceptionDescribe(pConnDA->penv);
(*(pConnDA->penv))->ExceptionClear(pConnDA->penv);
}
¿Este bloque de código capturará solo las excepciones de JNI? ¿Dónde se registrará la descripción de la excepción en la consola (STDERR)? ¿Cómo ingreso esto en el búfer, para poder pasarlo a mi módulo de registro?
Elliot Hughes
si invoca un método Java de JNI, llamando ExceptionCheck
despues volvere JNI_TRUE
si Java lanzó 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á en caso de error).
ExceptionDescribe
salidas a stderr. no hay una manera conveniente de hacer que vaya a otro lado, pero ExceptionOccurred
te da un jthrowable
si quieres jugar con él, o simplemente 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 el valor que devuelva; el código Java que llama nunca lo verá; en su lugar, verá la excepción pendiente.
-
ExceptionDescribe
imprime en “un canal de informe de errores del sistema, comostderr
”, es decir, depende de la implementación.– PJ Trail
8 de junio de 2016 a las 15:28
-
No funciona. El programa se ha bloqueado en la primera línea. He intentado algún caso de prueba/captura, verifique la Excepción pero aún no se ejecuta. ¿Cuál es la solución para eso?
– Bulma
12 de diciembre de 2017 a las 6:52
-
tú debe llamar
ExceptionClear()
siExceptionCheck() == JNI_TRUE
o el código java lanzará la excepción tan pronto como el control regrese a la JVM– Yusef Maali
21 de junio de 2020 a las 5:47
-
Supongamos que tiene una llamada anidada de C++ que encuentra un ‘env->ExceptionCheck()’, entonces preferiría lanzar una excepción de C++ y atraparla en el contexto inmediato del método JNI. Sin embargo, esta excepción no puede ser específica. O: ¿Hay alguna forma de solicitar el tipo de excepción de Java?
– Sam Ginrich
8 de enero de 2022 a las 16:53
oHo
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 de C++ y Java usando el JNI capa.
Respuesta corta
Vea la respuesta correcta de Elliott Hughes.
ejemplo reutilizable
Esta respuesta y los fragmentos son de dominio público o CC0 para facilitar su reutilización. Todo el código fuente aquí es compatible con versiones anteriores de C ++ 03.
Para reutilizar el fragmento anterior, haga lo siguiente:
- Reemplazar
mypackage::Exception
por su propia excepción de C++. - Si la excepción de Java correspondiente
my.group.mypackage.Exception
no está definido, entonces reemplace"my/group/mypackage/Exception"
por"java/lang/RuntimeException"
.
Captura excepciones de Java
Véase también el fragmento de 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.
Adaptar el código fuente generado por JNI
el siguiente archivo Java_my_group_mypackage_example.cpp
usa lo anterior rethrow_cpp_exception_as_java_exception()
función:
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 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
-
Generar
example.class
deexample.java
(usandojavac
o maven o su IDE favorito Eclipse/Netbeans/IntelliJ IDEA/…) -
Generar archivo de encabezado C/C++
Java_my_group_mypackage_example.h
deexample.class
usandojavah
-
¿Por qué es esto una macro? Completamente innecesario coliru.stacked-crooked.com/a/5cf4f3b6b1cb988f Además, no responde a la pregunta.
– Pato mugido
12 de agosto de 2014 a las 22:28
-
Hola @MooingDuck Gracias por tu enlace de coliru 🙂 He proporcionado más detalles en mi respuesta. Dígame si mi explicación es suficiente para comprender el uso y la personalización de la macro.
CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
. Mi objetivo es proporcionar una respuesta para ayudar a tantas personas como sea posible. Gracias de antemano por su ayuda 😉 Saludos– oho
28 de agosto de 2014 a las 12:56
-
Bueno, mis preguntas siguen vigentes. Intentaré ser más claro. Primero, ¿por qué una macro? Las macros son malas: stackoverflow.com/questions/14041453/…. En segundo lugar, la pregunta es “¿Cómo puedo obtener[catch] el [currently thrown] ¿Excepción de Java en la capa JNI?” Que su publicación en realidad no responde. :/
– Pato mugido
28 de agosto de 2014 a las 16:24
-
De hecho, esta técnica se puede utilizar sin macro y sin duplicación. Se puede poner en una función, como mostré con el enlace de coliru. Comprobar el
Java_group_package_class_function1
función en mi código.– Pato mugido
28 de agosto de 2014 a las 16:44
-
Aquí no respondes la pregunta.
– usuario207421
9 de mayo de 2015 a las 0:56
En el caso, cuando la excepción de Java ocurre en una llamada de C++ anidada, no se hace con un retorno simple, sino que prefiere eliminar los niveles intermedios de la pila de acuerdo con el mecanismo de lanzamiento.
Resolví esto con un
class JavaException : public std::exception
{
};
Luego, en una llamada anidada, donde se genera la excepción
void nestedMethod()
{
env->CallVoidMethod(...); // Java call creating Exception
if (env->ExceptionCheck())
{
throw JavaException();
}
}
Finalmente volviendo a Java
void JNI_method(JNIenv *env)
{
try
{
doComplexCall(); // --> nestedMethod()
}
catch(const JavaException&)
{
//coming from positive ExceptionCheck()
return;
}
}
Mira esto: developer.com/java/data/exception-handling-in-jni.html
– Behrouz.M
5 oct 2015 a las 13:36
@raypixar: Su enlace parece decirnos poco más que los conceptos básicos que se encuentran en la documentación oficial de JNI.
– PJ Trail
8 de junio de 2016 a las 14:56
En la pregunta JNI Obteniendo información de excepción: se intentó leer o escribir en la memoria protegida, encontrará un ejemplo de cómo llamar
toString
en la clase de excepción (u objeto). Dos cosas: • usted debe llamarExceptionClear
antes que casi cualquier otra cosa; • asegúrese de pasar el objeto de excepción si corresponde, no el objeto de clase de excepción (el error cometido por ese interrogador).– PJ Trail
8 jun 2016 a las 15:32