web-dev-qa-db-fra.com

La fonction JNI- FindClass renvoie la valeur null

J'ai une simple classe Java ("MainX") que je compile à l'aide d'un script Shell et d'Eclipse. Lorsque j'appelle la fonction env-> FindClass ("MainX"), le fichier MainX.class généré à partir du script renvoie la valeur null alors que le fichier MainX.class généré à partir d'Eclipse renvoie la classe et exécute ensuite la fonction runMainX.

Le fichier MainX.class généré se trouve dans le même dossier que l'exécutable JNI C++. 

MainX.Java

public class MainX {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println(new MainX().runMainX());
    }

    public String runMainX(){
        return ("0.789");
    }
}

JNIBinding.cpp

#define USER_CLASSPATH "."
....
....

JNIEnv* createVM (JavaVM **jvm)
{
    JNIEnv *env;                     /* pointer to native method interface */
    JavaVMInitArgs vm_args;              /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1]; //holds various JVM optional settings

    options[0].optionString = const_cast<char*>("-Djava.class.path="USER_CLASSPATH);
    vm_args.version = JNI_VERSION_1_6;       //version of Java platform
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface * pointer in env */
    long status = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);

    if (status == JNI_ERR){
       cout << "Fail: Unable to load JVM \t Exit" << endl;
    }
    else if (status == JNI_OK){
    cout << "CreateVM:\t\tJVM loaded successfully!" << endl ;
    }

    delete options;
    return env;
}

....
....

float invokeMainX(JavaVM **jvm, JNIEnv *env){

    jclass    mainClass ; //Returns a class object from a fully-qualified name, or NULL if the class cannot be found.
    jmethodID classConstructor; //Returns the method ID for an instance (nonstatic) method of a class 
    jobject   classObject;  //Constructs a new Java object
    jmethodID methodid;

    float outcome = 0;

    mainClass = env->FindClass("MainX");    //Returns a class object from a fully-qualified name, or NULL if the class cannot be found.
    if (mainClass==0) return 0;
         classConstructor = env->GetMethodID(mainClass, "<init>", "()V"); //Returns the method ID for an instance (nonstatic) method of a class 
    if (classConstructor==0) return -1;  
         classObject = env->NewObject(mainClass, classConstructor); //Constructs a new Java object
    if (classObject==0) return -2;  
         methodid = env->GetMethodID(mainClass, "runMainX", "()Ljava/lang/String;");
    if (methodid==0) return -3;
            jstring result = (jstring)env->CallObjectMethod(classObject, methodid); //returns the result of the calling method, an object 

....
....
}

Quelqu'un pourrait-il m'expliquer pourquoi cela se produit?

J'apprécie toute aide.

Une idée??? Merci d'avance

11
STiGMa

Dans la Documentation JNI for FindClass

 nom: nom de classe complet (c'est-à-dire un nom de package, délimité par "/", 
 suivi du nom de la classe).

Donc, en supposant que la classe soit dans le package your.package.name, je suppose que vous devrez remplacer

mainClass = env->FindClass("MainX");

avec

mainClass = env->FindClass("your/package/name/MainX");

J'espère que cela t'aides!

19
mbrenon

Je ne suis pas sûr de ce problème sur votre plate-forme, mais j'avais un problème similaire sur la plate-forme Android.

La méthode FindClass doit être appelée à partir d'un thread Java uniquement. L'implémentation de FindClass recherche un ClassLoader en traversant la pile d'appels en cours. Puisque vous essayez d'appeler FindClass depuis un thread natif, il n'y a pas de ClassLoader à rechercher. Regardez ceci JNI FAQ :

Si le nom de la classe semble correct, vous pourriez rencontrer un problème de chargeur de classe . FindClass souhaite démarrer la recherche de classe dans le chargeur de classe Associé à votre code. Il examine la pile d'appels, qui Ressemblera à quelque chose comme:

Foo.myfunc(Native Method)
Foo.main(Foo.Java:10)
dalvik.system.NativeStart.main(Native Method)

La méthode la plus utilisée est Foo.myfunc. FindClass trouve l'objet ClassLoader Associé à la classe Foo et l'utilise.

15
Ivan Mushketyk

J'ai CentOS 6 x86_64 et cela n'a pas fonctionné jusqu'à ce que j'ai modifié ces lignes

vm_args.version = JNI_VERSION_1_4;
...
options[0].optionString = (char *)"-Djava.class.path=/home/oscar/Projects/Java-C++";

j'ai aussi besoin d'exporter LD_LIBRARY_PATH:

javac HelloWorldApp.Java Bicycle.Java
g++ Prueba2.cpp -o Prueba2 -L/usr/lib64/gcj-4.4.4 -ljvm
export LD_LIBRARY_PATH=/usr/lib64/gcj-4.4.4/

J'espère que ça aide!

0
oml