У меня есть проблема с JNI, который весь день брал меня и будет, вероятно, управлять мной безумный, если я не зову на помощь.
В двух фразах: Я называю NewObject из метода JNI, и он хорошо работает, но когда я переместил этот код в другой метод, он отказывает.
Подробнее:
У меня есть этот простой класс, и я хочу создать экземпляры его из кода C/C++ JNI:
package example;
public class ModelDetails {
public ModelDetails() { ... }
}
Класс с собственным методом следующие:
package example;
public class JNIWrapper {
public native ModelDetails getModelDetails() throws SomeException;
}
Следующий код работал очень приятно:
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;
}
Однако, так как я должен сделать много вещей в этой функции Java_example_JNIWrapper_getModelDetails
, Я решил переместить создание этого объекта к другой функции:
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;
}
Таким образом, в Java_example_JNIWrapper_getModelDetails
Я просто звоню fillModelDetails(env, jobj);
Проблема состоит в том, что теперь я получаю ошибку шины в NewObject
строка.
Invalid memory access of location 0x9 eip=0x475fe1
Вопрос: кто-либо знает, почему я не должен вызывать конструктора из другого метода? Это кажется действительно странным.
Спасибо за любую подсказку, идею, комментарии...
Править:
Я только что добавил -Xcheck:jni
и получил эту ошибку:
FATAL ERROR in native method: Bad global or local ref passed to JNI
at example.JNIWrapper.getModelDetails(Native Method)
Таким образом, это дало мне идею, что проблема могла бы быть вызвана при помощи конструктора и идентификатора класса от глобальной переменной. Я переместил эти объявления в локальную переменную в методе JNI, и он работает.
Это действительно удивляет меня, потому что я использовал эти глобальные переменные с некоторого времени теперь и никогда не имел проблем..., что могло вызывать эту проблему?
Я отвечу на это, поскольку я нашел проблему, однако еще один вопрос остается относительно повторной использования JClass
и jmethodid
. Изменение этого вопроса в этом направлении не кажется организованным, поэтому я открою еще одну поток.
Решение было использование локальных переменных для
jclass modelDetailsClass = NULL;
jmethodID modelDetailsConstMid = NULL;
вместо глобальных переменных, которые я использовал раньше.