7 votes

Pourquoi mon code JNI ne parvient-il pas à trouver la méthode getMessage d'un jthrowable ?

J'essaie d'accéder au message dans un jthrowable tout en gérant une exception générée lorsque je ne parviens pas à trouver une classe. Cependant, je ne parviens pas à accéder à l'ID du message de getMessage() sur l'objet jthrowable, et je ne sais pas pourquoi. J'ai essayé de changer la signature de getMessage en "()Ljava/lang/String" (sans le point-virgule à la fin, mais c'est nécessaire, non ?) sans succès. Je suis très confus à ce sujet. J'ai même essayé de remplacer getMessage par toString, et que n'a pas fonctionné. Il est évident que je fais quelque chose de trivialement mauvais ici.

Voici le code que j'utilise :

jthrowable java_exception;
jclass java_class;
jmethodID method;

java_exception = (*jEnv)->ExceptionOccurred(jEnv);
assert (java_exception != NULL);
java_class = (*jEnv)->GetObjectClass (jEnv, java_exception);
assert (java_class != NULL);
method = (*jEnv)->GetMethodID (jEnv, java_class, "getMessage", "()Ljava/lang/String;");
if (method == NULL) {
printf ("Seriously, how do I get here?!\n");
(*jEnv)->ExceptionDescribe (jEnv);
return;
}

La sortie de ce code (entre autres choses) ressemble à ceci :

Sérieusement, comment je fais pour arriver ici ? !
Exception dans le thread "main" java.lang.NoClassDefFoundError : com/planet/core360/docgen/Processor

javap -p -s java.lang.Throwable me donne ça :

Compilé à partir de "Throwable.java".
public class java.lang.Throwable extends java.lang.Object implements java.io.Serializable{
...
public java.lang.String getMessage() ;
Signature : ()Ljava/lang/String ;
...

8voto

Chris R Points 6336

Ok, donc on dirait que mon problème était que GetObjectClass ne se comporte pas comme on s'y attend sur un jthrowable, ou du moins les résultats de cette opération ne sont pas utiles pour obtenir des méthodes. Remplacer cette partie du code par ceci fonctionne :

java_class = (*jEnv)->FindClass (jEnv, "java/lang/Throwable");
method = (*jEnv)->GetMethodID (jEnv, java_class, "getMessage", "()Ljava/lang/String;");

Sacrément bizarre, ça. J'espère que ça aidera quelqu'un d'autre à l'avenir, cependant.

3voto

Chris Jester-Young Points 102876

J'ai essayé votre approche, et ça a marché pour moi. Quelques précisions toutefois : j'utilise l'interface C++ (mais cela ne devrait pas faire de différence), et j'utilise Java 6 update 10, édition x64, sur Ubuntu 8.04. Peut-être la version de Java et/ou la plate-forme utilisée feront-elles une différence.

#include <cstdio>
#include <jni.h>

int
main(int argc, char** argv)
{
    if (argc != 3) {
        std::fprintf(stderr, "usage: %s class message\n", argv[0]);
        return 1;
    }

    JavaVM* jvm;
    void* penv;
    JavaVMInitArgs args = {JNI_VERSION_1_6};

    if (jint res = JNI_CreateJavaVM(&jvm, &penv, &args)) {
        std::fprintf(stderr, "Can's create JVM: %d\n", res);
        return -res;
    }

    JNIEnv* env(static_cast<JNIEnv*>(penv));
    jint vers(env->GetVersion());
    std::printf("JNI version %d.%d\n", vers >> 16, vers & 0xffff);

    env->ThrowNew(env->FindClass(argv[1]), argv[2]);
    jthrowable exc(env->ExceptionOccurred());
    std::printf("Exception: %p\n", exc);
    if (exc) {
        jclass exccls(env->GetObjectClass(exc));
        jclass clscls(env->FindClass("java/lang/Class"));

        jmethodID getName(env->GetMethodID(clscls, "getName", "()Ljava/lang/String;"));
        jstring name(static_cast<jstring>(env->CallObjectMethod(exccls, getName)));
        char const* utfName(env->GetStringUTFChars(name, 0));

        jmethodID getMessage(env->GetMethodID(exccls, "getMessage", "()Ljava/lang/String;"));
        jstring message(static_cast<jstring>(env->CallObjectMethod(exc, getMessage)));
        char const* utfMessage(env->GetStringUTFChars(message, 0));

        std::printf("Exception: %s: %s\n", utfName, utfMessage);
        env->ReleaseStringUTFChars(message, utfMessage);
        env->ReleaseStringUTFChars(name, utfName);
    }
    return -jvm->DestroyJavaVM();
}

J'ai utilisé jnitest java/lang/InternalError 'Hello, world!' pour mes tests ; n'hésitez pas à essayer avec d'autres types d'exceptions !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X