在JNI代码中抛出exception的最佳方法是什么?

我想要一个一致的和简单的方法来在JNI代码中抛出exception; 处理链式exception的东西(隐式地从env-> ExceptionOccurred方法中,或者通过参数显式的,无论哪种方式都是好的),并且每当我想要这样做的时候,我都省去了查找构造器。 以上所有都是用C语言编写的,尽pipe我可以根据需要从C ++翻译它。

有没有人有这样的东西,他们可以分享?

我们只编写我们想要抛出的每种exceptiontypes的实用方法。 这里有些例子:

jint throwNoClassDefError( JNIEnv *env, char *message ) { jclass exClass; char *className = "java/lang/NoClassDefFoundError"; exClass = (*env)->FindClass( env, className); if (exClass == NULL) { return throwNoClassDefError( env, className ); } return (*env)->ThrowNew( env, exClass, message ); } jint throwNoSuchMethodError( JNIEnv *env, char *className, char *methodName, char *signature ) { jclass exClass; char *exClassName = "java/lang/NoSuchMethodError" ; LPTSTR msgBuf; jint retCode; size_t nMallocSize; exClass = (*env)->FindClass( env, exClassName ); if ( exClass == NULL ) { return throwNoClassDefError( env, exClassName ); } nMallocSize = strlen(className) + strlen(methodName) + strlen(signature) + 8; msgBuf = malloc( nMallocSize ); if ( msgBuf == NULL ) { return throwOutOfMemoryError ( env, "throwNoSuchMethodError: allocating msgBuf" ); } memset( msgBuf, 0, nMallocSize ); strcpy( msgBuf, className ); strcat( msgBuf, "." ); strcat( msgBuf, methodName ); strcat( msgBuf, "." ); strcat( msgBuf, signature ); retCode = (*env)->ThrowNew( env, exClass, msgBuf ); free ( msgBuf ); return retCode; } jint throwNoSuchFieldError( JNIEnv *env, char *message ) { jclass exClass; char *className = "java/lang/NoSuchFieldError" ; exClass = (*env)->FindClass( env, className ); if ( exClass == NULL ) { return throwNoClassDefError( env, className ); } return (*env)->ThrowNew( env, exClass, message ); } jint throwOutOfMemoryError( JNIEnv *env, char *message ) { jclass exClass; char *className = "java/lang/OutOfMemoryError" ; exClass = (*env)->FindClass( env, className ); if ( exClass == NULL ) { return throwNoClassDefError( env, className ); } return (*env)->ThrowNew( env, exClass, message ); } 

这样,很容易find它们,您的代码完成编辑器将帮助您键入它们,并且可以传递简单的参数。

我相信你可以扩展这个来处理链式exception,或其他更复杂的方法。 这足以满足我们的需求。

我只使用2行:

  sprintf(exBuffer, "NE%4.4X: Caller can %s %s print", marker, "log", "or"); (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), exBuffer); 

生产:

  Exception in thread "main" java.lang.Exception: NE0042: Caller can log or print. 

我的代码以Java开始,调用C ++,然后再调用Java来查找,获取和设置字段值。

如果有人在寻找一个C ++的方法find这个页面,我将继续这样做:

我现在正在做的是用C ++ try / catch块封装我的JNI方法体,

 JNIEXPORT void JNICALL Java_com_pany_jni_JNIClass_something(JNIEnv* env, jobject self) { try { ... do JNI stuff // return something; if not void. } catch (PendingException e) // (Should be &e perhaps?) { /* any necessary clean-up */ } } 

PendingException被简单地声明为:

 class PendingException {}; 

我从C ++调用任何JNI后调用以下方法,所以如果Javaexception状态指示错误,我将立即保释并让普通的Javaexception处理将(Native方法)行添加到堆栈跟踪,而给C ++提供清理时的机会:

 PendingException PENDING_JNI_EXCEPTION; void throwIfPendingException(JNIEnv* env) { if (env->ExceptionCheck()) { throw PENDING_JNI_EXCEPTION; } } 

我的Java堆栈跟踪看起来像一个失败的env-> GetFieldId()调用:

 java.lang.NoSuchFieldError: no field with name='opaque' signature='J' in class Lcom/pany/jni/JniClass; at com.pany.jni.JniClass.construct(Native Method) at com.pany.jni.JniClass.doThing(JniClass.java:169) at com.pany.jni.JniClass.access$1(JniClass.java:151) at com.pany.jni.JniClass$2.onClick(JniClass.java:129) at android.view.View.performClick(View.java:4084) 

如果我调用Java方法抛出:

  java.lang.RuntimeException: YouSuck at com.pany.jni.JniClass.fail(JniClass.java:35) at com.pany.jni.JniClass.getVersion(Native Method) at com.pany.jni.JniClass.doThing(JniClass.java:172) 

我不能说在包含Javaexception的C ++内的另一个Javaexception,我认为这是你的问题的一部分 – 我还没有发现需要这样做 – 但如果我这样做,我要么做一个围绕本地方法的Java级别的包装器,或者只是扩展我的exception抛出方法来取得一个jthrowable,并用丑陋的东西replaceenv-> ThrowNew()调用:这是不幸的Sun没有提供一个ThrowNew的版本, jthrowable。

 void impendNewJniException(JNIEnv* env, const char *classNameNotSignature, const char *message) { jclass jClass = env->FindClass(classNameNotSignature); throwIfPendingException(env); env->ThrowNew(jClass, message); } void throwNewJniException(JNIEnv* env, const char* classNameNotSignature, const char* message) { impendNewJniException(env, classNameNotSignature, message); throwIfPendingException(env); } 

我不会考虑caching(exception)类构造函数的引用,因为exception不应该是一个普通的控制stream机制,所以它应该不会太慢。 我想,无论如何,查找速度并不是很慢,因为Java可能会自行caching这类事情。