1,Java调用Native code在Native code中抛出异常,在Java侧捕捉异常。
2,Native code调用Java侧代码,在Java侧抛出异常,在Native code侧捕捉异常。
我们从以下一个例子详细分析:
class CatchThrow {
//在Native code执行完后抛出"非法参数异常"
private native void doit()
throws IllegalArgumentException;
//Java侧代码执行完后抛出"空指针异常"
private void callback() throws NullPointerException {
throw new NullPointerException("CatchThrow.callback");
}
public static void main(String args[]) {
//在Java侧捕获Native code中抛出的异常
CatchThrow c = new CatchThrow();
try {
c.doit();
} catch (Exception e) {
//捕获异常打印出信息
System.out.println("In Java:/n/t" + e);
}
}
static {
System.loadLibrary("CatchThrow");
}
}
JNIEXPORT void JNICALL
Java_CatchThrow_doit(JNIEnv *env, jobject obj)
{
//定义一个jtrowable对象,用来抛出异常
jthrowable exc;
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid =
(*env)->GetMethodID(env, cls, "callback", "()V");
if (mid == NULL) {
return;
}
//调用Java侧callback函数
(*env)->CallVoidMethod(env, obj, mid);
//等Java侧callback函数执行完后,去捕获异常信息
exc = (*env)->ExceptionOccurred(env);
if (exc) {
/* We don't do much with the exception, except that
we print a debug message for it, clear it, and
throw a new exception. */
jclass newExcCls;
//打印出异常信息
(*env)->ExceptionDescribe(env);
//清除异常信息
(*env)->ExceptionClear(env);
newExcCls = (*env)->FindClass(env,
"java/lang/IllegalArgumentException");
if (newExcCls == NULL) {
/* Unable to find the exception class, give up. */
return;
}
//抛出"参数异常“
(*env)->ThrowNew(env,newExcCls,"thrownfromCcode");
}
}
以上例子说明了如何在java与Native code中抛出异常与捕获异常信息。
针对Native code侧异常抛出的方式,整合一个通用函数如下:
void
JNU_ThrowByName(JNIEnv*env,constchar*name,constchar*msg)
{
jclass cls = (*env)->FindClass(env, name);
/*if cls is NULL, an exception has already been thrown */
if (cls != NULL) {
(*env)->ThrowNew(env, cls, msg);
}
/* free the local ref */
(*env)->DeleteLocalRef(env, cls);
}
以上是抛出异常的介绍。
下面介绍异常处理:
在调用JNI函数时候经常因为失败返回NULL,但是返回NULL的话,coder并不知道那个逻辑出现了exception。针对这个问题,我们现在封装一个函数调用与异常处理的函数出来:
jvalue
JNU_CallMethodByName(JNIEnv *env,
jboolean *hasException,
jobject obj,
const char *name,
const char *descriptor, ...)
{
va_list args;
jclass clazz;
jmethodID mid;
jvalue result;
if ((*env)->EnsureLocalCapacity(env, 2) == JNI_OK) {
clazz = (*env)->GetObjectClass(env, obj);
mid = (*env)->GetMethodID(env, clazz, name,
descriptor);
if (mid) {
const char *p = descriptor;
/* skip over argument types to find out the
return type */
while (*p != ')') p++;
/* skip ')' */
p++;
va_start(args, descriptor);
switch (*p) {
case 'V':
(*env)->CallVoidMethodV(env, obj, mid, args);
break;
case '[':
case 'L':
result.l = (*env)->CallObjectMethodV(
env, obj, mid, args);
break;
case 'Z':
result.z = (*env)->CallBooleanMethodV(
env, obj, mid, args);
break;
case 'B':
result.b = (*env)->CallByteMethodV(
env, obj, mid, args);
break;
case 'C':
result.c = (*env)->CallCharMethodV(
env, obj, mid, args);
break;
case 'S':
result.s = (*env)->CallShortMethodV(
env, obj, mid, args);
break;
case 'I':
result.i = (*env)->CallIntMethodV(
env, obj, mid, args);
break;
case 'J':
result.j = (*env)->CallLongMethodV(
env, obj, mid, args);
break;
case 'F':
result.f = (*env)->CallFloatMethodV(
break;
case 'D':
result.d = (*env)->CallDoubleMethodV(
env, obj, mid, args);
break;
default:
(*env)->FatalError(env, "illegal descriptor");
}
va_end(args);
}
(*env)->DeleteLocalRef(env, clazz);
}
if (hasException) {
*hasException = (*env)->ExceptionCheck(env);
}
return result;
}
其中 ExceptionCheck 函数在Java2 SDK release1.2 中有跟新,与ExceptionOccurred的功能类似。
如果在release1.1中要重写如下:
if (hasException) {
jthrowable exc = (*env)->ExceptionOccurred(env);
*hasException = exc != NULL;
(*env)->DeleteLocalRef(env, exc);
}
应用示例:
JNIEXPORT void JNICALL
Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
printf("In C/n");
JNU_CallMethodByName(env, NULL, obj, "callback", "()V");
}
以上是对JNI Exception应用的简单总结!