64

JNI コードで例外をスローするための一貫した簡単な方法が必要です。チェーンされた例外を処理するもの (env->ExceptionOccurred メソッドから暗黙的に、またはパラメーターによって明示的に、どちらの方法でも良い)、これを行うたびにコンストラクターを検索する手間を省くことができます。上記はすべて C であることが望ましいですが、必要に応じて C++ から翻訳することもできます。

SOの誰かが共有できるこのようなものを持っていますか?

4

4 に答える 4

54

スローする例外の種類ごとにユーティリティ メソッドをコーディングするだけです。ここではいくつかの例を示します。

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 );
}

そうすれば、それらを簡単に見つけることができ、コード補完エディターを使用して入力することができ、単純なパラメーターを渡すことができます。

これを拡張して、チェーンされた例外やその他のより複雑なアプローチを処理できると確信しています。これは私たちのニーズを満たすのに十分でした。

于 2008-10-27T16:29:00.703 に答える
28

私は単に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.
于 2012-03-21T21:01:22.577 に答える
6

私のコードは Java で始まり、C++ を呼び出します。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 例外ステータスがエラーを示している場合は、すぐに保釈し、通常の 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例外をラップすることについて話すことはできません.または、例外をスローするメソッドを拡張して jthrowable を取得し、 env->ThrowNew() 呼び出しを醜いものに置き換えます。残念なことに、Sun は、 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はおそらくそのようなことのために独自のキャッシングを行うからです.

于 2012-08-31T12:56:22.080 に答える