JNI Exception

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应用的简单总结!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值