13

I have a simple java class ("MainX") that I compile using a shell script and eclipse. When I invoke the env->FindClass("MainX") function the MainX.class file generated from the script returns null whereas the MainX.class file generated from eclipse returns the class and executes thereafter the runMainX function.

The generated MainX.class file is located in the same folder with the JNI C++ executable.

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 

....
....
}

Could someone explain me why this occurs?

I appreciate any help.

Any idea??? Thanks in advance

STiGMa
  • 906
  • 3
  • 11
  • 24

3 Answers3

26

From the JNI Documentation for FindClass:

name: a fully-qualified class name (that is, a package name, delimited by "/", 
      followed by the class name).

So assuming the class is in the package your.package.name, I guess you'll have to replace

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

with

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

Hope this helps!

Sean Bright
  • 118,630
  • 17
  • 138
  • 146
mbrenon
  • 4,851
  • 23
  • 25
  • Thanks mbrenon. However, I do not have any package. It's in the src directory – STiGMa Oct 01 '13 at 12:46
  • I see. No idea then, i'm used to using JNI in the Android context where packages are mandatory as far as i know... – mbrenon Oct 01 '13 at 14:39
  • Is it different in mac OS? In my Mac M1, If I use . as delimeter, then it is working but not working with / as delimeter. – Vivek Mangal May 23 '22 at 10:04
16

I am not sure about this problem on your platform, but I had a similar problem on Android platform.

The FindClass method should be called from Java thread only. FindClass's implementation is looking for a ClassLoader by traversing the current call-stack. Since you are trying to call the FindClass from a native thread, there is no ClassLoader to look for. Take a look at this JNI FAQ:

If the class name looks right, you could be running into a class loader issue. FindClass wants to start the class search in the class loader associated with your code. It examines the call stack, which will look something like:

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

The topmost method is Foo.myfunc. FindClass finds the ClassLoader object associated with the Foo class and uses that.

Ivan Mushketyk
  • 8,107
  • 7
  • 50
  • 67
0

I have CentOS 6 x86_64 and it didn't work until I modified this lines:

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

also I need to export 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/

I hope it helps!

oml
  • 115
  • 2
  • 8