1

次のようなJavaクラスがあるとします。

    public class Test
    {
        static { System.loadLibrary("test"); }
        public native int foo();
    }

foo()メソッドがいくつかのJNI呼び出しを実行していて、これらの呼び出しの1つが失敗した(つまり、例外をスローした)とします。次に、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がジントではないということです。たとえばAndroidでは、コンパイル時に次 の警告が表示されます。警告:returnは、キャストなしでポインタから整数を作成します

ここで問題は、ジントを返すJNIメソッド内で例外がスローされた場合に何を返す必要があるかということです。

4

2 に答える 2

4

コード(またはライブラリ)がJavaでを生成Exceptionする場合、どの値を返すかは関係ありません。Javaはそれを無視します。明らかに、互換性のあるタイプである必要があります。そのため0、例に戻ることは理にかなっているように思われます。コードが戻ると、Javaランタイムは、Exceptionが発生したことを認識し、それを伝播し続け、関数の戻り値を無視します。

もちろん、互換性のあるタイプを返す必要があります。関数がポインタを返すように宣言されていない場合にNULLにキャストされるため、単純にを返さないでください。これは適切でない場合があります。int

ただし、明らかに、C関数を呼び出す場合、それらは。を発生させませんException。したがって、整数をエラー条件(-1たとえば)にマップしてからExceptionJavaでスローするか、時間をかけてExceptionJNIでを構築することができます。

于 2011-12-03T17:02:11.280 に答える
0

編集:下部のプリプロセッサマクロの代わりに関数を使用したこのエレガントな回答   も参照してください。


エドワードトムソンの答えを完成させるための例を提供します。

この例では、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");            \
  }
于 2013-03-08T08:27:09.457 に答える