我正在尝试为应用程序创建插件。该插件需要用 c++ 编写。我想在 Windows 和 Mac 上使用该插件,因此用 Java 编写该插件会很棒。
我的问题,还有另一个使用 Java 的插件。由于它们使用相同的主应用程序,因此已经有一个正在运行的 JavaVM。
JavaVM *jvm = NULL;
jsize jvm_count = 0;
jint res=0;
res = JNI_GetCreatedJavaVMs (&jvm, 1, &jvm_count);
我的问题: 如何更改/修改现有 JavaVM 的类路径?或者我如何创建一个新的/第二个JavaVM?
我尝试通过 JNI 加载我的 jar 文件:
/* URL CLASS */
jclass URLcls;
URLcls = env->FindClass("java/net/URL");
/* URL CLASS CONSTRUCTOR*/
jmethodID URLclsMid;
URLclsMid = env->GetMethodID(URLcls, "<init>","(Ljava/lang/String;)V");
/* URL OBJECT */
jobject URLobj;
jstr = env->NewStringUTF("file:/path/to/test/file/test.jar");
URLobj = env->NewObject(URLcls, URLclsMid, jstr);
/* URL Array */
jobjectArray URLArray;
URLArray = env->NewObjectArray(1, URLcls, URLobj);
/*Thread Class*/
jclass ThreadCLS;
ThreadCLS = env->FindClass("java/lang/Thread");
/*Static Method currentThread*/
jmethodID ThreadCLS_currentThread;
ThreadCLS_currentThread = env->GetStaticMethodID(ThreadCLS, "currentThread","()Ljava/lang/Thread;");
/*get current Thread Object*/
jobject currentThread;
currentThread = env->CallStaticObjectMethod(ThreadCLS, ThreadCLS_currentThread);
/* getContextClassLoader method */
jmethodID currentThread_getContextClassLoader;
currentThread_getContextClassLoader = env->GetMethodID(ThreadCLS, "getContextClassLoader","()Ljava/lang/ClassLoader;");
/* ClassLoader Class */
jclass ClassLoaderCLS;
ClassLoaderCLS = env->FindClass("java/lang/ClassLoader");
/* get ClassLoader Object */
jobject classLoader = env->CallObjectMethod(currentThread, currentThread_getContextClassLoader);
/* URLClassLoader Class */
jclass URLClassLoaderCLS;
URLClassLoaderCLS = env->FindClass("java/net/URLClassLoader");
/* Static Method newInstance */
jmethodID URLClassLoaderCLS_newInstance;
URLClassLoaderCLS_newInstance = env->GetStaticMethodID(URLClassLoaderCLS, "newInstance","([Ljava/net/URL;Ljava/lang/ClassLoader;)Ljava/net/URLClassLoader;");
/* get new URLClassLoader Instance */
jobject myURLClassLoaderInstance;
myURLClassLoaderInstance = env->CallStaticObjectMethod(URLClassLoaderCLS, URLClassLoaderCLS_newInstance, URLArray, classLoader);
/* get setContextClassLoader Method */
jmethodID currentThread_setContextClassLoader;
currentThread_setContextClassLoader = env->GetMethodID(ThreadCLS, "setContextClassLoader","(Ljava/lang/ClassLoader;)V");
/* trying to set the ClassLoader from the current Thread */
env->CallVoidMethod(currentThread, currentThread_setContextClassLoader, myURLClassLoaderInstance);
/* get loadClass Method */
jmethodID loadClass;
loadClass = env->GetMethodID(URLClassLoaderCLS, "loadClass","(Ljava/lang/String;)Ljava/lang/Class;");
/* get a Class from my test.jar*/
jstring methodString = env->NewStringUTF("de.domain.sayHello");
jclass myClass = (jclass)env->CallObjectMethod(myURLClassLoaderInstance, loadClass, methodString);
/*working till here*/
jmethodID myClassMethod;
myClassMethod = env->GetMethodID(myClass, "doIt","()Ljava/lang/String;");
if (myClassMethod == NULL) {
// Method of Class "de.domain.sayHello" not found
}
我可以做什么来更改类路径?或者加载我的 jar 文件?
谢谢 丽莎
最佳答案
我已经解决了我的问题。我没有设法以某种方式设置或影响类路径,以便我可以使用:
jmethodID myClassMethod;
myClassMethod = env->GetMethodID(myClass, "doIt","()Ljava/lang/String;");
if (myClassMethod == NULL) {
// Method of Class "de.domain.sayHello" not found
}
取而代之的是,我使用 Java Reflection 创建了我的类的一个对象。
查找我的 Java 类:(在我的问题代码中的“/工作到这里/”之后)
/* Class CLASS */
jclass Classcls = env->FindClass("java/lang/Class");
/* String CLASS */
jclass StringCls = env->FindClass("java/lang/String");
jstring methodString = env->NewStringUTF("de.domain.sayHello");
jclass myJavaClass = (jclass)env->CallObjectMethod(MyURLClassLoaderInstance, URLClassLoaderCLS_loadClass, methodString);
从我的 Java 类获取一个对象:
/* CLASS newInstance Method*/
jmethodID ClassNewInstanceMid = env->GetMethodID(Classcls, "newInstance","()Ljava/lang/Object;");
jobject myObject = env->CallObjectMethod(myJavaClass, ClassNewInstanceMid);
这样我就从我的 Java 类中得到了一个对象。 (调用了默认构造函数)
使用 jobject,我可以通过 java 反射调用我的对象的方法。我将带有应用程序路径的 Sring 传递给了我的 Java 方法。
在 Java 端,我加载了应用程序:
import java.io.File;
public class sayHello {
public static native void sayHi(String message, int times);
public sayHello()
{
System.out.println("object created :) ");
}
public void doIt(String test)
{
File myfile = new File(test);
if(myfile.exists())
System.load(myfile.getAbsolutePath());
else
System.out.println("Something went wrong :( ");
sayHi("C++ Funktion Call out of Java",5);
}
}
在我的 C++ 插件中我实现了这个功能:
JNIEXPORT void JNICALL Java_de_domain_sayHello_sayHi
(JNIEnv *localEnv, jclass clazz, jstring message, jint times)
{
int myT = times;
for(int i=0;i<myT;i++)
fprintf(stderr,"%s\n", localEnv->GetStringUTFChars(message, NULL));
}
有趣的事情: 在 JNICALL 方法 (Java_de_domain_sayHello_sayHi) 中,我可以通过 JNI 找到我的调用:
jclass myCLS = env->FindClass("de/domain/sayHello");
if(myCLS != NULL){
//class found
}
在这个函数内部,我是否使用函数中的 JNIEnv“localEnv”或“env”(全局变量)并不重要
谢谢 丽莎
关于java - c++ 插件 -> JNI -> Java 类路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20328012/