Reputation: 946
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
Upvotes: 15
Views: 43892
Reputation: 8285
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.
Upvotes: 16
Reputation: 4941
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!
Upvotes: 27
Reputation: 175
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!
Upvotes: 0