我想要一個一致的和簡單的方法來在JNI代碼中拋出異常;處理鏈式異常的東西(隱式地來自env-> ExceptionOccurred方法,或者通過參數明確指示,無論哪種方式都是好的),並且每次我想要這樣做時都可以節省我查找構造函數的工作。以上所有內容最好都用C語言編寫,儘管我可以根據需要從C++翻譯它。在JNI代碼中拋出異常的最佳方法?
有沒有人有這樣的東西,他們可以分享?
我想要一個一致的和簡單的方法來在JNI代碼中拋出異常;處理鏈式異常的東西(隱式地來自env-> ExceptionOccurred方法,或者通過參數明確指示,無論哪種方式都是好的),並且每次我想要這樣做時都可以節省我查找構造函數的工作。以上所有內容最好都用C語言編寫,儘管我可以根據需要從C++翻譯它。在JNI代碼中拋出異常的最佳方法?
有沒有人有這樣的東西,他們可以分享?
我們只是爲每種我們想拋出的異常類型編寫實用方法。下面是一些例子:
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);
}
這樣一來,很容易找到他們,你的代碼完成編輯器將幫助您鍵入他們,你可以通過簡單的參數。
我相信你可以擴展它以處理鏈式異常或其他更復雜的方法。這足以滿足我們的需求。
剛剛發現這個,謝謝。但是,`throwNoClassDefError`中的錯誤條件不會導致無限遞歸和不可避免的堆棧溢出?我承認,這絕不應該發生,但這似乎不是處理它的適當方式。也許回到`java.lang.error`和`abort()`之類的東西,如果不行的話。 – 2010-09-19 00:42:54
是的,我也看到了。同意。我無法讓我的ThrowNew()調用做_anything_,即使它們返回NULL(即成功)。 Nothin的永遠容易... – 2012-02-14 15:25:44
我只需使用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++的辦法找到這個頁面,我將與此犁地:
什麼我現在做的是包裝我的JNI方法體了一個C++ try/catch塊,
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後,下面的方法++,因此,如果Java異常狀態指示S上的錯誤,我會立刻保釋,並讓普通的Java異常處理添加(本機方法)線堆棧跟蹤,同時給了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)
我不能跟包裝在C++中另一個Java異常中的Java異常,我認爲這是你問題的一部分 - 我還沒有發現需要這樣做 - 但是如果我這樣做了,我要麼用一個Java級別的包裝器本地方法,或者只是擴展我的異常拋出方法來獲取jThrowable,並用醜陋的東西替換env-> 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);
}
我不會考慮緩存(異常)類的構造函數的引用,因爲異常不應該是一個通用控制流機制,所以如果他們慢它不應該的問題。我想,無論如何,查找速度並不是很慢,因爲Java可能會爲這類事情做自己的緩存。
'處理鏈式異常'是否意味着您的代碼會注意到從Java到C++的返回時會捕獲Java級別的異常,並將其包裝在其他一些異常中,並將新異常從C++重新提交給Java? – 2012-08-31 11:49:01