<span style="font-family:Comic Sans MS;font-size:14px;">class CatchThrow { private native void doit() throws IllegalArgumentException; private void callback() throwsNullPointerException { throw newNullPointerException("CatchThrow.callback"); } public static void main(String args[]) { CatchThrow c = new CatchThrow(); try { c.doit(); } catch (Exception e) { System.out.println("InJava:\n\t" + e); } } static { System.loadLibrary("CatchThrow"); } }</span>Main方法调用本地方法doit,doit方法的实现如下:
<span style="font-family:Comic Sans MS;font-size:14px;">JNIEXPORT void JNICALL Java_CatchThrow_doit(JNIEnv*env, jobject obj) { jthrowable exc; jclass cls = (*env)->GetObjectClass(env,obj); jmethodID mid = (*env)->GetMethodID(env, cls,"callback", "()V"); if (mid == NULL) { return; } (*env)->CallVoidMethod(env, obj, mid); 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 exceptionclass, give up. */ return; } (*env)->ThrowNew(env, newExcCls,"thrown from C code"); } }</span>
<span style="font-family:Comic Sans MS;font-size:14px;">void JNU_ThrowByName(JNIEnv *env, const char *name,const char *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); }</span>
<span style="font-family:Comic Sans MS;font-size:14px;"> /* a class in the Java programming language */ public class Window { long handle; int length; int width; static native void initIDs(); static { initIDs(); } } /* C codethat implements Window.initIDs */ jfieldID FID_Window_handle; jfieldID FID_Window_length; jfieldID FID_Window_width; JNIEXPORT void JNICALL Java_Window_initIDs(JNIEnv *env, jclass classWindow) { FID_Window_handle = (*env)->GetFieldID(env, classWindow,"handle", "J"); if (FID_Window_handle == NULL) { /* important check. */ return; /* erroroccurred. */ } FID_Window_length = (*env)->GetFieldID(env, classWindow,"length", "I"); if (FID_Window_length == NULL) { /* important check. */ return; /* erroroccurred. */ } FID_Window_width = (*env)->GetFieldID(env, classWindow,"width", "I"); /* no checks necessary; weare about to return anyway */ }</span>
<span style="font-family:Comic Sans MS;font-size:14px;">public class Fraction { // details such as constructors omitted int over, under; public int floor() { return Math.floor((double)over/under); } } /* Native code that callsFraction.floor. Assume method ID MID_Fraction_floor has been initializedelsewhere. */ void f(JNIEnv*env, jobject fraction) { jint floor = (*env)->CallIntMethod(env, fraction, MID_Fraction_floor); /* important: check if an exception wasraised */ if ((*env)->ExceptionCheck(env)) { return; } ... /* use floor */ }</span>
<span style="font-family:Comic Sans MS;font-size:14px;">JNIEXPORT void JNICALL Java_pkg_Cls_f(JNIEnv*env, jclass cls, jstring jstr) { const jchar *cstr =(*env)->GetStringChars(env, jstr); if (c_str == NULL) { return; } ... if (...) { /* exception occurred */ (*env)->ReleaseStringChars(env,jstr, cstr); return; } ... /* normal return */ (*env)->ReleaseStringChars(env, jstr,cstr); } </span>
<span style="font-family:Comic Sans MS;font-size:14px;"> 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 findout 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( env,obj, mid, args); 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; }</span>
<span style="font-family:Comic Sans MS;font-size:14px;"> JNIEXPORT void JNICALL Java_InstanceMethodCall_nativeMethod(JNIEnv*env, jobject obj) { printf("In C\n"); JNU_CallMethodByName(env, NULL, obj,"callback", "()V"); }</span>
测试代码:
/** * 异常处理 */ public native void doExcepton() throws IllegalArgumentException; /** * * @throws NullPointerException */ public void excepton() throws NullPointerException { throw new NullPointerException("doExcepton.excepton"); }
/** * 异常处理 */ JNIEXPORT void JNICALL Java_com_example_jniandroid_service_CFunction_doExcepton( JNIEnv * env, jobject obj) { jthrowable exc; jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetMethodID(env, cls, "excepton", "()V"); if (mid == NULL) { LOGI(" MID IS NULL"); return; } (*env)->CallVoidMethod(env, obj, mid); exc = (*env)->ExceptionOccurred(env); //有异常 if (exc) { jclass newExcCls; (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); newExcCls = (*env)->FindClass(env,"java/lang/IllegalArgumentException"); if (newExcCls == NULL) { return; } (*env)->ThrowNew(env, newExcCls, "thrown from C code doExcepton"); } }