Hello all,
I have a problem with JNI that has taken me all day and will probably drive me insane if I don't call for help.
In two phrases: I call a NewObject from a JNI method and it works fine, but when I moved this code to another method, it crashes.
More details:
I have this simple class, and I want to create instances of it from the JNI C/C++ code:
package example;
public class ModelDetails {
public ModelDetails() { ... }
}
The class with the native method is as follows:
package example;
public class JNIWrapper {
public native ModelDetails getModelDetails() throws SomeException;
}
The following code worked very nicely:
jclass modelDetailsClass = NULL;
jmethodID modelDetailsConstMid = NULL;
JNIEXPORT jobject JNICALL Java_example_JNIWrapper_getModelDetails
(JNIEnv *env, jobject jobj) {
cout << "getModelDetails c++" << endl;
// ModelDetails class
if (!modelDetailsClass) { // reuse class
modelDetailsClass = env->FindClass("example/ModelDetails");
}
if (!modelDetailsClass) { // check if findclass was successful
throwJavaException(env, "Could not get class ModelDetails");
return NULL;
}
cout << "model detail class: " << modelDetailsClass << endl;
// constructor
if (!modelDetailsConstMid) { // reuse method id
modelDetailsConstMid = env->GetMethodID(modelDetailsClass, "<init>", "()V");
}
if (!modelDetailsConstMid) { // check if getmethodid was successful
throwJavaException(env, "Could not get ModelDetails constructor method id");
return NULL;
}
// create object
jobject mdetails = env->NewObject(modelDetailsClass, modelDetailsConstMid);
if (!mdetails) {
throwJavaException(env, "Could not create ModelDetails instance");
return NULL;
}
return mdetails;
}
However, since I have to do a lot of things in this function Java_example_JNIWrapper_getModelDetails
, I decided to move the creation of this object to another function:
jobject fillModelDetails(JNIEnv *env, jobject jobj) {
cout << "fillModelDetails" << endl;
// ModelDetails class
if (!modelDetailsClass) { // reuse class
modelDetailsClass = env->FindClass("example/ModelDetails");
}
if (!modelDetailsClass) { // check if findclass was successful
throwJavaException(env, "Could not get class ModelDetails");
return NULL;
}
cout << "model detail class: " << modelDetailsClass << endl;
// constructor
if (!modelDetailsConstMid) { // reuse method id
modelDetailsConstMid = env->GetMethodID(modelDetailsClass, "<init>", "()V");
}
if (!modelDetailsConstMid) { // check if getmethodid was successful
throwJavaException(env, "Could not get ModelDetails constructor method id");
return NULL;
}
// create object
jobject mdetails = env->NewObject(modelDetailsClass, modelDetailsConstMid);
if (!mdetails) {
throwJavaException(env, "Could not create ModelDetails instance");
return NULL;
}
return mdetails;
}
This way, in Java_example_JNIWrapper_getModelDetails
I just call fillModelDetails(env, jobj);
The problem is that now I get a bus error at the NewObject
line.
Invalid memory access of location 0x9 eip=0x475fe1
Question: Does anyone know why I should not be calling a constructor from another method? It seems really weird.
Thanks for any tip, idea, comments...
Edit:
I've just added -Xcheck:jni
and got this error:
FATAL ERROR in native method: Bad global or local ref passed to JNI
at example.JNIWrapper.getModelDetails(Native Method)
So this gave me the idea that the problem might be caused by using the constructor and class id from a global variable. I moved these declarations to a local variable in the JNI method and it works.
This really astonishes me because I've been using these global variables from some time now and never had any problems... what could be causing this problem?