我将 C++ 与 JNI 一起使用,目的是列出给定 Java 类中的所有方法并列出给定 java 应用程序中的所有类名。我试图执行以下操作来获取 Minecraft 主类,但它无法正常工作,我想弄清楚如何调试它以便自己修复它。为此,我需要能够列出所有课程。这将使调试任何其他问题变得更加容易。
static jobject classLoader;
static jmethodID mid_findClass;
static void setupClassLoader()
{
jclass c_Thread = Java::Env->FindClass("java/lang/Thread");
jclass c_Map = Java::Env->FindClass("java/util/Map");
jclass c_Set = Java::Env->FindClass("java/util/Set");
jclass c_ClassLoader = Java::Env->FindClass("java/lang/ClassLoader");
jmethodID mid_getAllStackTraces = Java::Env->GetStaticMethodID(c_Thread, "getAllStackTraces", "()Ljava/util/Map;");
jmethodID mid_keySet = Java::Env->GetMethodID(c_Map, "keySet", "()Ljava/util/Set;");
jmethodID mid_toArray = Java::Env->GetMethodID(c_Set, "toArray", "()[Ljava/lang/Object;");
jmethodID mid_getContextClassLoader = Java::Env->GetMethodID(c_Thread, "getContextClassLoader", "()Ljava/lang/ClassLoader;");
mid_findClass = Java::Env->GetMethodID(c_ClassLoader, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
jmethodID mid_currentThread = Java::Env->GetStaticMethodID(c_Thread, "currentThread", "()Ljava/lang/Thread;");
jobject obj_stackTracesMap = Java::Env->CallStaticObjectMethod(c_Thread, mid_getAllStackTraces);
jobject obj_threadsSet = Java::Env->CallObjectMethod(obj_stackTracesMap, mid_keySet);
jobjectArray threads = (jobjectArray) Java::Env->CallObjectMethod(obj_threadsSet, mid_toArray);
jint szThreads = Java::Env->GetArrayLength(threads);
for (int i = 0; i < szThreads; i++) {
jobject thread = Java::Env->GetObjectArrayElement(threads, i);
jobject classLoaderObj = Java::Env->CallObjectMethod(thread, mid_getContextClassLoader);
if (classLoaderObj) { // How can I print all class names here instead of using NewStringUTF with a class name I presume to exist
jstring className = Java::Env->NewStringUTF("minecraft.client.Minecraft");
jobject minecraftClass = Java::Env->CallObjectMethod(classLoaderObj, mid_findClass, className);
if (minecraftClass) { // This is never true
classLoader = classLoaderObj;
Java::Env->DeleteLocalRef(minecraftClass);
break;
}
}
Java::Env->DeleteLocalRef(thread);
}
好吧,假设我通过弄清楚如何打印类然后设法获得正确的类来解决上述问题,我将需要能够打印类的方法及其名称和返回类型。以下是我的方法,但我不知道如何从 jClass 对象实际打印所有方法信息。
inline static jclass clazz;
Java::AssignClass("example.Example", clazz);
bool Java::AssignClass(std::string name, jclass& out)
{
jstring className = Java::Env->NewStringUTF(name.c_str());
jobject findClass = Java::Env->CallObjectMethod(classLoader, mid_findClass, className);
if (findClass) {
out = (jclass) findClass;
return true;
}
return false;
}
列出给定 Java 类中的所有方法
java.lang.Class.getMethods()
将为您提供由调用它的 Class
对象表示的类的公共方法,包括继承的方法。 java.lang.Class.getDeclaredMethods()
将为您提供目标类直接声明的任何可见性的所有方法。在这两者之间,也许Class.getSuperclass()
,您可以识别任何感兴趣的类的所有方法。
您可以通过 JNI 调用这些方法,但 JNI API 没有自己的函数来完成同样的事情。
列出给定 java 应用程序中的所有类名
您可以列出或提取相关 JAR 文件的内容以查找其中的类名称。他们的包名称可能会让您知道哪些是最感兴趣的。然而,没有好的 Java API 可以通过编程方式获取已知或可用类的详尽列表。 JNI当然不提供这样的。
我试图[使用活动线程的上下文类加载器]来获取 Minecraft 主类
这是一种看似合理的方法,假设您知道要查找的类的完全限定名称。但这并不是一件确定的事情。可以玩一些有趣的
ClassLoader
游戏来防止以这种方式访问给定的班级或班级组。我并不认为 Minecraft 可能会玩这样的游戏,但这也不是不可能的。
但是,您已经在检索所有线程的堆栈跟踪,并且如果 Minecraft 的初始线程仍在运行,那么您可以从该线程的堆栈跟踪的最后一个元素中获取游戏入口点类的名称。如果有多个线程,那么您可能不知道该看哪个,但出于调试目的,这将为您提供一个可供考虑的简短列表。
我需要能够列出所有课程。
我想对于“全部”的一些定义。但即使有一个相当严格的定义,这也不是你通常可以从
ClassLoader
获得的东西。我会找到另一种方式。