Pergunta

Eu gostaria de uma forma consistente e simples para lançar exceções em código JNI; algo que alças acorrentado exceções (implicitamente do env-> método ExceptionOccurred, ou explicitamente por parâmetros, de qualquer forma é bom) e salva-me olhando para cima construtores cada vez que eu quero fazer isso. Tudo o que precede está de preferência em C, embora pudesse traduzir-lo a partir de C ++ em necessidade.

Alguém no SO ter algo como isto que eles podem compartilhar?

Foi útil?

Solução

apenas métodos de utilitário de código para cada um dos tipos de exceções que queremos jogar. Aqui estão alguns exemplos:

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

Dessa forma, é fácil encontrá-los, o seu editor de código-conclusão vai ajudar você a digitá-los, e você pode passar parâmetros simples.

Eu tenho certeza que você poderia expandir isso para lidar com exceções encadeadas, ou outras abordagens mais complicado. Isso foi o suficiente para atender às nossas necessidades.

Outras dicas

Eu simplesmente usar 2 linhas:

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

Produz:

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

Meu código começa em Java, invoca C ++, que então chama Java volta para coisas como constatação, recebendo, e definir valores de campo.

No caso de alguém à procura de um C ++ abordagem encontra esta página, eu vou arar com esta:

O que eu estou fazendo agora está passando os corpos de método JNI-se com um C ++ bloco 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 */
    }
}

onde PendingException é declarado trivialmente:

class PendingException {};

e estou invocando o método seguinte depois de invocar qualquer JNI de C ++, por isso, se o estado de exceção Java indica um erro, eu vou socorrer imediatamente e deixar o manuseio normal exceção Java adicionar o (método nativo) linha para a pilha traço, dando o C ++ a oportunidade de limpar enquanto desenrolando:

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

Meu Java pilha aparência de traço como este para uma chamada falhou 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)

e bastante semelhante se eu chamar-se a um método Java que lança:

 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)

Eu não posso falar para embalar a exceção Java dentro de outra exceção Java de dentro C ++, que eu acho que faz parte da sua pergunta - eu não encontrei a necessidade de fazer isso - mas se eu fiz, eu tinha tanto fazê-lo com um invólucro de nível Java em torno dos métodos nativos, ou apenas estender meus métodos de arremesso de exceção para tomar um jthrowable e substituir a chamada env-> ThrowNew () com algo feio: é lamentável Sun não forneceu uma versão do ThrowNew que tomou um 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);
}

Eu não consideraria referências caching (exceção) construtor da classe porque as exceções não devem ser um mecanismo de controle de fluxo de costume, por isso não deve importa se eles são lentos. Imagino look-up não é terrivelmente lento de qualquer maneira, já que Java presumivelmente faz o seu próprio cache para esse tipo de coisa.

Eu vou colocar uma resposta mais completa e geral para quem precisa de um pouco mais explicações como eu preciso antes.

Em primeiro lugar é bom para definir o seu método com um Throw Exception para que o IDE irá pedir try / catch.

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

Eu decido para IOException sobre Exception por causa este .

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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top