Frage

würde ich eine konsistente und einfache Art und Weise mag Ausnahmen in JNI Code zu werfen; etwas, die verkettete Ausnahme behandelt (implizit aus der env-> ExceptionOccurred Methode oder explizit von Parametern, so oder so gut ist) und erspart mich Konstrukteuren aufzublicken jedes Mal, wenn ich dies tun will. Alle der oben genannten sind vorzugsweise in C, obwohl ich es von C ++ bei Bedarf übersetzen könnte.

Hat jemand auf SO etwas davon haben, dass sie gemeinsam nutzen können?

War es hilfreich?

Lösung

Wir sind gerade Code Utility-Methoden für jede der verschiedenen Arten von Ausnahmen wir werfen wollen. Hier sind einige Beispiele:

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

Auf diese Weise ist es einfach, sie zu finden, Code-Completion-Editor hilft Ihnen, sie in geben, und Sie können einfache Parameter übergeben.

Ich bin sicher, dass Sie diese gekettet Ausnahmen zu behandeln erweitern könnte, oder andere, kompliziertere Ansätze. Das war genug, um unsere Bedürfnisse zu erfüllen.

Andere Tipps

Ich verwende nur 2 Zeilen:

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

Erzeugt:

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

Mein Code beginnt in Java, C ++ ruft, die Java dann für Dinge wie die Suche nach wieder aufruft, erhalten, und Setzen von Feldwerten.

Falls jemand auf der Suche nach einem C ++ Ansatz dieser Seite findet, werde ich mit diesem pflügen auf:

Was ich jetzt mache, ist meine JNI-Methode Körper sich mit einem C ++ Einwickeln try / catch-Block,

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 */
    }
}

Dabei gilt PendingException erklärt trivialer:

class PendingException {};

und ich den Aufruf die folgende Methode nach einem für JNI aus C ++ aufrufen, so dass, wenn der Java-Ausnahmestatus einen Fehler anzeigt, werde ich Kaution sofort und lassen Sie die normale Java Ausnahmebehandlung die (Mutter Methode) Linie zu dem Stapel hinzufügen Spur, während die C ++ die Möglichkeit zu geben, um aufzuräumen, während Abwickeln:

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

Mein Java-Stack-Trace sieht wie folgt für einen ausgefallenen env-> GetFieldId () Aufruf:

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)

und ziemlich ähnlich, wenn ich auf eine Java-Methode aufrufen, die wirft:

 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)

Ich kann nicht auf das Einwickeln der Java-Ausnahme in einer anderen Java-Ausnahme aus C ++ sprechen, die ich denke, ein Teil Ihrer Frage ist - ich habe nicht die Notwendigkeit festgestellt, dass zu tun - aber wenn ich es täte, würde ich entweder tun sie es mit einem Java-Level-Wrapper um die nativen Methoden, oder einfach nur meine Ausnahme werfenden Methoden erweitern, um eine jthrowable zu nehmen und das env-> ThrowNew () mit etwas ersetzen ugly: es bedauerlich Sun ist nicht eine Version von ThrowNew lieferte das dauerte eine 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);
}

Ich würde nicht Caching (Ausnahme) Klassenkonstruktors Referenzen, weil Ausnahmen nicht sein soll ein üblicher Steuerstrommechanismus, sollte so sollte es keine Rolle, ob sie langsam sind. Ich stelle mir vor Nachschau sowieso nicht sehr langsam, da Java vermutlich für diese Art der Sache sein eigenes Caching der Fall ist.

Ich werde stellen eine vollständigere und allgemeine Antwort für die brauchen ein wenig mehr Erklärungen, wie ich vor müssen.

Zuerst ist schön, Ihre Methode mit einem Throw Exception so einzustellen, dass die IDE für try / catch fragen.

public native int func(Param1, Param2, Param3) throws IOException;

Ich entscheide, für IOException über Exception wegen diese .

JNIEXPORT int JNICALL Java_YourClass_func
(int Param1, int Param2, int Param3) {
    if (Param3 == 0) { //something wrong
        jclass Exception = env->FindClass("java/lang/Exception");
        env->ThrowNew(Exception, "Can't divide by zero."); // Error Message
    }
    return (Param1+Param2)/Param3;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top