JVMTI 调用 toString();在来自 C++ 代码的 Java 对象上
JVMTI Invoke toString(); on an Java object from C++ code
所以,我试图调用 toString();对象上的方法(在本例中为枚举)。这立即使我的应用程序崩溃。我假设,因为 toString();方法不是直接在枚举中声明,而是从对象 class(在本例中为枚举)继承而来,它无法找到该方法,因此会导致错误。
bool is_miss() {
// the enum I want to invoke toString() on, the type() method works just fine and returns the jobject
jobject rt_type = type();
// I assume that this is where i'm doing something wrong
// Edit: My assumption was right, this is the line that causes the crash
jmethodID method = m_jenv->GetMethodID(m_jenv->GetObjectClass(rt_type), "toString", "()Ljava/lang/String;");
jstring str = (jstring)m_jenv->CallObjectMethod(rt_type, method);
jboolean is_copy = jboolean{ true };
return std::string(m_jenv->GetStringUTFChars(str, &is_copy));
}
如何声明 m_jenv:
JNIEnv* m_jenv;
这是初始化:
// ... other code ...
jsize count;
if (JNI_GetCreatedJavaVMs(&m_jvm, 1, &count) != JNI_OK || count == 0) {
return;
}
jint res = m_jvm->GetEnv((void**)&m_jenv, JNI_VERSION_1_6);
if (res == JNI_EDETACHED) {
res = m_jvm->AttachCurrentThread((void**)&m_jenv, nullptr);
}
if (res != JNI_OK) {
return;
}
// ... other code ...
但是,初始化工作正常,m_jenv 字段是通过一个全局变量访问的,该变量包含一个包含 JNIEnv* 字段的 class。它被无数方法访问,甚至在 is_miss() 方法的 class 中也是如此,只有这个方法导致错误。
如何通过 JVMTI 在枚举(或一般的 Java 对象)上调用 toString 方法?
我已经做了一些试验,现在我找到了解决方案,所以它为什么不起作用是有道理的。
我没有尝试直接在 class 中查找 toString() 方法,而是通过了 class 在 java/lang/Enum 的 class 路径中找到的 class (或 java/lang/Object 对于 non-enum 类型)到 getMethodID() 函数。
jmethodID method = m_jenv->GetMethodID(m_jenv->FindClass("java/lang/Enum"), "toString", "()Ljava/lang/String;");
然后将我的 jobject 传递给 CallObjectMethod()。
jobject result = m_jenv->CallObjectMethod(rt_type, method);
所以,我试图调用 toString();对象上的方法(在本例中为枚举)。这立即使我的应用程序崩溃。我假设,因为 toString();方法不是直接在枚举中声明,而是从对象 class(在本例中为枚举)继承而来,它无法找到该方法,因此会导致错误。
bool is_miss() {
// the enum I want to invoke toString() on, the type() method works just fine and returns the jobject
jobject rt_type = type();
// I assume that this is where i'm doing something wrong
// Edit: My assumption was right, this is the line that causes the crash
jmethodID method = m_jenv->GetMethodID(m_jenv->GetObjectClass(rt_type), "toString", "()Ljava/lang/String;");
jstring str = (jstring)m_jenv->CallObjectMethod(rt_type, method);
jboolean is_copy = jboolean{ true };
return std::string(m_jenv->GetStringUTFChars(str, &is_copy));
}
如何声明 m_jenv:
JNIEnv* m_jenv;
这是初始化:
// ... other code ...
jsize count;
if (JNI_GetCreatedJavaVMs(&m_jvm, 1, &count) != JNI_OK || count == 0) {
return;
}
jint res = m_jvm->GetEnv((void**)&m_jenv, JNI_VERSION_1_6);
if (res == JNI_EDETACHED) {
res = m_jvm->AttachCurrentThread((void**)&m_jenv, nullptr);
}
if (res != JNI_OK) {
return;
}
// ... other code ...
但是,初始化工作正常,m_jenv 字段是通过一个全局变量访问的,该变量包含一个包含 JNIEnv* 字段的 class。它被无数方法访问,甚至在 is_miss() 方法的 class 中也是如此,只有这个方法导致错误。
如何通过 JVMTI 在枚举(或一般的 Java 对象)上调用 toString 方法?
我已经做了一些试验,现在我找到了解决方案,所以它为什么不起作用是有道理的。
我没有尝试直接在 class 中查找 toString() 方法,而是通过了 class 在 java/lang/Enum 的 class 路径中找到的 class (或 java/lang/Object 对于 non-enum 类型)到 getMethodID() 函数。
jmethodID method = m_jenv->GetMethodID(m_jenv->FindClass("java/lang/Enum"), "toString", "()Ljava/lang/String;");
然后将我的 jobject 传递给 CallObjectMethod()。
jobject result = m_jenv->CallObjectMethod(rt_type, method);