2011-12-03 96 views
0

假設我有一個Java類是這樣的:JNI INT方法從外返回

​​

假設,把foo()方法做一些JNI調用,而這些調用的一個失敗(IE,拋出一個異常)。然後,我想從JNI代碼返回並拋出Java中拋出的異常。例如:

jint Java_Test_foo(JNIEnv* env, jobject thiz) 
    { 
     jstring foobar = (*env)->NewStringUTF(env, "Hello from JNI !"); 
     if(foobar == NULL) // Not enough memory. OutOfMemoryError is thrown 
      return NULL; // Return immediately to get exception thrown in Java 
     // Do other stuff 
     ... 
     return some_computed_jint; 
    } 

問題是return NULL不是jint。以Android爲例,編譯時會出現這樣的警告: 警告:返回從指針中取得整數而沒有轉換

現在的問題是:如果在返回jint的JNI方法中拋出異常,應該返回什麼?

回答

4

如果您的代碼(或庫)在Java中引發了Exception,則返回的值無關緊要,Java將忽略它。顯然,它需要是兼容的類型 - 所以在你的例子中返回0似乎是有道理的,或者任何你感到滿意的。當您的代碼返回時,Java運行時會注意到Exception已被引發並繼續傳播它並忽略函數的返回值。

您當然會需要返回兼容的類型。不要簡單地返回NULL,因爲當函數未被聲明爲返回一個指針時它將被轉換爲int,這可能不合適。

顯然,當您調用C函數時,那些不會引發Exception。因此,您可以將整數映射到錯誤條件(例如,-1),然後使用Java拋出Exception,或者可以花時間在JNI中構建Exception

+0

所以你說Java(不在JNI下)返回值並不重要,當拋出一個異常。這是真的,因爲當拋出異常時,java方法永遠不會到達return語句。我和你在那裏。 但是你是否在說如果我調用一個「拋出」異常的JNI方法,並且我沒有使用ExceptionClear清除它,那麼無論我從JNI返回什麼,返回到Java時都會拋出異常?如果是,那麼我可以返回任何jint,並且jint在Java端永遠不可見,對吧? – foens

+1

是的,這是正確的。 –

0

編輯:  另請參閱this elegant answer using a function instead of the bottom preprocessor macro


我提供了一個例子來完成Edward Thomson's answer

在這個例子中JNI非void功能return 0;

JNIEXPORT jlong JNICALL Java_group_package_class_function1(
          JNIEnv *env, jobject object, jlong value) 
{ 
    try 
    { 
    /* ... my processing ... */ 
    return jlong(result); 
    } 
    CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION 
    return 0; 
} 

JNIEXPORT jstring JNICALL Java_group_package_class_function2(
          JNIEnv *env, jobject object, jlong value) 
{ 
    try 
    { 
    /* ... my processing ... */ 
    jstring jstr = env->NewStringUTF("my result"); 
    return jstr; 
    } 
    CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION 
    return 0; 
} 

JNIEXPORT void JNICALL Java_group_package_class_function3(
          JNIEnv *env, jobject object, jlong value) 
{ 
    try 
    { 
    /* ... my processing ... */ 
    } 
    CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION 
} // void function => no "return 0;" statement 

C預處理器宏CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION存在於所有上述JNI函數的末尾。

#define CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION    \ 
                    \ 
    catch (const package::Exception& e)        \ 
    {                \ 
    jclass jc = env->FindClass("group/package/Exception");  \ 
    if(jc) env->ThrowNew (jc, e.what());       \ 
    /* if null => NoClassDefFoundError already thrown */   \ 
    }                \ 
    catch (const std::bad_alloc& e)         \ 
    {                \ 
    /* OOM exception */           \ 
    jclass jc = env->FindClass("java/lang/OutOfMemoryError");  \ 
    if(jc) env->ThrowNew (jc, e.what());       \ 
    }                \ 
    catch (const std::ios_base::failure& e)       \ 
    {                \ 
    /* IO exception */           \ 
    jclass jc = env->FindClass("java/io/IOException");   \ 
    if(jc) env->ThrowNew (jc, e.what());       \ 
    }                \ 
    catch (const std::exception& e)         \ 
    {                \ 
    /* unknown exception */          \ 
    jclass jc = env->FindClass("java/lang/Error");    \ 
    if(jc) env->ThrowNew (jc, e.what());       \ 
    }                \ 
    catch (...)              \ 
    {                \ 
    /* Oops I missed identifying this exception! */    \ 
    jclass jc = env->FindClass("java/lang/Error");    \ 
    if(jc) env->ThrowNew (jc, "unexpected exception");   \ 
    }