4

In C++ (JNI), I get an already running JVM using the following JNI function:

JNI_GetCreatedJavaVMs(&jvm,1,&vmnb);

Then I attach the current thread using the following code:

jvm->AttachCurrentThread((void**)&env, NULL);

Question: How can I set classpath in that case? Thanks.

Note: Creating a new JVM and passing the classpath in vm_args to the new JVM is not an option for me.

waheed
  • 134
  • 1
  • 8
  • The class path is a system property that is used to configure the application class loader during startup. Changing the system property is easy, but for a JVM whose initialization has been completed already, it has no real effect on the class loading. Generally, JVMs supporting changes to the application class loader (e.g. via JVMTI) only allow appending new entries to the end. – Holger Jul 21 '17 at 10:07
  • In fact, appending a new entry to the current classpath was enough. I have achieved that through Java (as mentioned in my answer). – waheed Jul 21 '17 at 13:39

2 Answers2

4

As it is possible to append the classpath inside Java, so I found an alternative way to set classpath inside C++ through Java. As I'm already running JVM, I use the append classpath method (void addPath(String path), that is posted in this answer), inside the Java program that is already running in the JVM. I access the addPath java method from C++ using JNI calls to append the classpath. The classpath passed to addPath method from C++ should not include "-Djava.class.path" and it should be just complete path to the .jar file, i.e. "C:\\folder\\abc.jar". So sequence is: 1) get already running JVM, attach current thread to the JVM, get JNI environment pointer and then call addPath java function (of another running thread) from C++ using JNI. I can now access the classes of new classpath (.jar file) successfully from C++.

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
waheed
  • 134
  • 1
  • 8
1

I ran into this issue, and I did not have the option to call back into the JVM, so I implemented the whole add_path busniess on the JNI side.

void add_path(JNIEnv* env, const std::string& path)
{
    const std::string urlPath = "file:/" + path;
    jclass classLoaderCls = env->FindClass("java/lang/ClassLoader");
    jmethodID getSystemClassLoaderMethod = env->GetStaticMethodID(classLoaderCls, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
    jobject classLoaderInstance = env->CallStaticObjectMethod(classLoaderCls, getSystemClassLoaderMethod);
    jclass urlClassLoaderCls = env->FindClass("java/net/URLClassLoader");
    jmethodID addUrlMethod = env->GetMethodID(urlClassLoaderCls, "addURL", "(Ljava/net/URL;)V");
    jclass urlCls = env->FindClass("java/net/URL");
    jmethodID urlConstructor = env->GetMethodID(urlCls, "<init>", "(Ljava/lang/String;)V");
    jobject urlInstance = env->NewObject(urlCls, urlConstructor, env->NewStringUTF(urlPath.c_str()));
    env->CallVoidMethod(classLoaderInstance, addUrlMethod, urlInstance);
    std::cout << "Added " << urlPath << " to the classpath." << std::endl;
}
laht
  • 86
  • 3
  • This just proves that making JavaVM a singleton per process was a bad move by Java. They should have atleast made it so multiple users of a process could use different class paths. – user13947194 Jul 06 '23 at 22:07