Description
In my C++ application class JNIXMLDocument which made some JAVA method calls. In the constructor of JNIXMLDocument class I attach current thread and set it to my class member JNIEnv* m_JavaEnv and then use it in all methods. Also in the constructor I am trying to find my JAVA class com/fido/android/framework/service/XMLDOMDocument and set it to class member m_XMLDocumentClass and also get that class object from the class and set it to class member m_XMLDocumentObject.
C++ Code
class JNIXMLDocument
{
/* Constructor **/
JNIXMLDocument()
{
/* Get JNI right version and set it. **/
jint interface_id = JNI_VERSION_1_2;
#ifdef JNI_VERSION_1_2
interface_id = JNI_VERSION_1_2;
#else
interface_id = JNI_VERSION_1_1;
#endif
/* Trying to attach current thread. **/
int res = g_JavaVirtualMachine->GetEnv(&m_JavaEnv, interface_id);
if (res == JNI_EDETACHED || res == JNI_EVERSION) {
res = g_JavaVirtualMachine->AttachCurrentThread(&m_JavaEnv, NULL);
}
/* Get Class from Java **/
m_XMLDocumentClass = m_JavaEnv->FindClass("com/fido/android/framework/service/XMLDOMDocument");
if (m_XMLDocumentClass != NULL) {
/* Call java class constructor. **/
jmethodID constructor = m_JavaEnv->GetMethodID(m_XMLDocumentClass , "<init>", "()V");
m_XMLDocumentObject = m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);
}
}
bool Initialize()
{
jmethodID method = m_JavaEnv->GetMethodID(m_XMLDocumentClass, "Initialize", "()Lorg/w3c/dom/Document;");
jobject document = m_JavaEnv->CallObjectMethod(m_XMLDocumentObject , method);
}
private:
JNIEnv* m_JavaEnv;
jclass m_XMLDocumentClass;
jobject m_XMLDocumentObject;
};
C++ Code (Right way)
class JNIXMLDocument
{
/* Constructor **/
JNIXMLDocument()
{
/* Get JNI right version and set it. **/
jint interface_id = JNI_VERSION_1_2;
#ifdef JNI_VERSION_1_2
interface_id = JNI_VERSION_1_2;
#else
interface_id = JNI_VERSION_1_1;
#endif
JNIEnv* env;
/* Trying to attach current thread. **/
int res = g_JavaVirtualMachine->GetEnv(&env, interface_id);
if (res == JNI_EDETACHED || res == JNI_EVERSION) {
res = g_JavaVirtualMachine->AttachCurrentThread(&env, NULL);
}
/* Get Class from Java **/
jclass localClass = env->FindClass("com/fido/android/framework/service/XMLDOMDocument");
if (localClass != NULL) {
m_XMLDocumentClass = env->NewGlobalRef(localClass);
/* Call java class constructor. **/
jmethodID constructor = env->GetMethodID(localClass, "<init>", "()V");
jobject localObject = env->NewObject(m_XMLDocumentClass , constructor);
m_XMLDocumentObject = env->NewGlobalRef(localObject );
}
}
bool Initialize()
{
}
private:
jclass m_XMLDocumentClass;
jobject m_XMLDocumentObject;
};
Questions
- Is it right to set JNI interface pointer (
JNIEnv* m_JavaEnv) in the constructor once and use it in the whole code ? - Is it right to set
jclass m_XMLDocumentClassin the constructor and than use that variable in the all methods ? - Is it right to set
jobject m_XMLDocumentObjectin the constructor in this waym_JavaEnv->NewObject(m_XMLDocumentClass , constructor);or maybe I must callNewGlobalRef. - What problems can appear if my application work not in the same thread (use many threads) ?
No. It is thread-specific. That’s what Attach/DetachCurrentThread are for. The only way this can work is if the C++ object is constructed and destroyed in the same thread.
No. It is a local reference, and it expires when the JNI method it was acquired in returns. You must save as a global or weak reference unless it is only going to be used within a single JNI method.
No: see above.
Yes, as above.
Mainly JVM crashes. The JVM assumes you follow all the rules in the JNI specification. So do that.