从异常返回的 JNI int 方法
Posted
技术标签:
【中文标题】从异常返回的 JNI int 方法【英文标题】:JNI int method returning from exception 【发布时间】:2011-12-03 16:31:14 【问题描述】:假设我有一个这样的 Java 类:
public class Test
static System.loadLibrary("test");
public native int foo();
假设 foo() 方法正在执行一些 JNI 调用,并且其中一个调用失败(IE,抛出异常)。然后我想从 JNI 代码返回并在 Java 中抛出异常。例如:
jint Java_Test_foo(JNIEnv* env, jobject thiz)
jstring foobar = (*env)->NewStringUTF(env, "Hello from JNI !");
if(foobar == NULL) // Not enough memory. OutOfMemoryError is thrown
return NULL; // Return immediately to get exception thrown in Java
// Do other stuff
...
return some_computed_jint;
问题是return NULL
不是一个jint。例如,在 android 中,我会在编译时收到此警告:
警告:return 从没有强制转换的指针中生成整数。
现在的问题是:如果在返回 jint 的 JNI 方法中抛出异常,我应该返回什么?
【问题讨论】:
【参考方案1】:如果您的代码(或库)在 Java 中引发 Exception
,那么无论您返回什么值,Java 都会忽略它。显然,它需要是兼容的类型 - 因此在您的示例中返回 0
似乎是有道理的,或者您喜欢的任何东西。当您的代码返回时,Java 运行时会注意到已引发 Exception
并继续传播它并忽略您的函数的返回值。
当然,您需要返回兼容的类型。不要简单地返回NULL
,因为当函数未声明返回指针时,这将被强制转换为int
,这可能不合适。
但很明显,当您调用 C 函数时,这些函数不会引发 Exception
。因此,您可以将整数映射到错误条件(例如 -1
),然后在 Java 中抛出 Exception
,或者您可以花时间在 JNI 中构建 Exception
。
【讨论】:
所以你在 Java 中的说法(而不是在 JNI 中)当抛出异常时返回值并不重要。这是真的,因为当抛出异常时,java 方法永远不会到达 return 语句。我在那里和你在一起。但是你是说如果我调用一个“抛出”异常的 JNI 方法并且我没有使用 ExceptionClear 清除它,那么无论我从 JNI 返回什么,返回到 Java 时都会抛出异常?如果是,那么我可以返回任何 jint,并且该 jint 在 Java 端永远不可见,对吧?【参考方案2】:编辑: 另见this elegant answer using a function instead of the bottom preprocessor macro。
我提供一个例子来完成Edward Thomson's answer。
在此示例中,JNI 非 void 函数 return 0;
JNIEXPORT jlong JNICALL Java_group_package_class_function1(
JNIEnv *env, jobject object, jlong value)
try
/* ... my processing ... */
return jlong(result);
CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
return 0;
JNIEXPORT jstring JNICALL Java_group_package_class_function2(
JNIEnv *env, jobject object, jlong value)
try
/* ... my processing ... */
jstring jstr = env->NewStringUTF("my result");
return jstr;
CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
return 0;
JNIEXPORT void JNICALL Java_group_package_class_function3(
JNIEnv *env, jobject object, jlong value)
try
/* ... my processing ... */
CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
// void function => no "return 0;" statement
C 预处理器宏 CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
出现在上述所有 JNI 函数的末尾。
#define CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION \
\
catch (const package::Exception& e) \
\
jclass jc = env->FindClass("group/package/Exception"); \
if(jc) env->ThrowNew (jc, e.what()); \
/* if null => NoClassDefFoundError already thrown */ \
\
catch (const std::bad_alloc& e) \
\
/* OOM exception */ \
jclass jc = env->FindClass("java/lang/OutOfMemoryError"); \
if(jc) env->ThrowNew (jc, e.what()); \
\
catch (const std::ios_base::failure& e) \
\
/* IO exception */ \
jclass jc = env->FindClass("java/io/IOException"); \
if(jc) env->ThrowNew (jc, e.what()); \
\
catch (const std::exception& e) \
\
/* unknown 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, "unexpected exception"); \
【讨论】:
以上是关于从异常返回的 JNI int 方法的主要内容,如果未能解决你的问题,请参考以下文章