Just a simple question: Is it possible to call a java function from c/c++ ?
7 Answers
Yes you can, but it is a little convoluted, and works in a reflective/non type safe way (example uses the C++ api which is a little cleaner than the C version). In this case it creates an instance of the Java VM from within the C code. If your native code is first being called from Java then there is no need to construct a VM instance
#include<jni.h>
#include<stdio.h>
int main(int argc, char** argv) {
JavaVM *vm;
JNIEnv *env;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = 1;
// Construct a VM
jint res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
// Construct a String
jstring jstr = env->NewStringUTF("Hello World");
// First get the class that contains the method you need to call
jclass clazz = env->FindClass("java/lang/String");
// Get the method that you want to call
jmethodID to_lower = env->GetMethodID(clazz, "toLowerCase",
"()Ljava/lang/String;");
// Call the method on the object
jobject result = env->CallObjectMethod(jstr, to_lower);
// Get a C-style string
const char* str = env->GetStringUTFChars((jstring) result, NULL);
printf("%s\n", str);
// Clean up
env->ReleaseStringUTFChars(jstr, str);
// Shutdown the VM.
vm->DestroyJavaVM();
}
To compile (on Ubuntu):
g++ -I/usr/lib/jvm/java-6-sun/include \
-I/usr/lib/jvm/java-6-sun/include/linux \
-L/usr/lib/jvm/java-6-sun/jre/lib/i386/server/ -ljvm jnitest.cc
Note: that the return code from each of these methods should be checked in order to implement correct error handling (I've ignored this for convenience). E.g.
str = env->GetStringUTFChars(jstr, NULL);
if (str == NULL) {
return; /* out of memory */
}
-
1+1 for example. Might also want to include links/examples of setting up the headers, function signatures, etc? Commented Jun 14, 2009 at 16:25
-
your solution is great but what how to load or set classpath that we created For example HelloWorld.java i.e
env->FindClass("HelloWorld");
Commented Jan 18, 2017 at 12:15 -
1This worked for me, thank goodness. I upvoted, and let me just mention that I used "-Wl,-rpath,${lib_dir}", without quotes of course, where lib_dir is the directory where libjvm.so lies (I used 'find /usr/lib/jvm/ -name "libjvm.so"', and took the dirname for the actual jvm lib directory in my environment). The -Wl,-rpath,${lib_dir} in the link (or compile/link) step (i.e. g++) makes it so you don't have to specify lib_dir in LD_LIBRARY_PATH at runtime. Commented Sep 19, 2018 at 19:13
Yes it is, but you have to do it via JNI: http://java.sun.com/javase/6/docs/technotes/guides/jni/index.html
-
3I've seen JNI used to call C++ from Java. Didn't know it worked the other way as well.– KieveliCommented Jun 14, 2009 at 13:35
-
4Strange, I've always seen it more commonly used to provide access to C++ libraries from Java, but it works both ways. Commented Jun 14, 2009 at 13:38
-
1@CBBailey "provide access to C++ libraries from Java" means "call C++ from Java". No? I feel like you're both saying the same thing: "Commonly used to call [C++ code] from Java". Commented Aug 1, 2020 at 19:07
Take a look at the invocation API. This enables you to load and start up a JVM from within your native application, and then to invoke methods upon it from the application.
Briefly (from the linked doc)
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
JNI_CreateJavaVM(&jvm, &env, &vm_args);
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
The following function allows you to create the VM.
JNIEnv* create_vm(JavaVM ** jvm)
{
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options[2];
options[0].optionString = "-Djava.class.path=.";
options[1].optionString = "-DXcheck:jni:pedantic";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 2;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE; // remove unrecognized options
int ret = JNI_CreateJavaVM(jvm, (void**) &env, &vm_args);
if (ret < 0) printf("\n<<<<< Unable to Launch JVM >>>>>\n");
return env;
}
Compile the famous Hello World program. The following function attempts to call the main method of the HelloWorld Program.
int main(int argc, char* argv[])
{
JNIEnv* env;
JavaVM* jvm;
env = create_vm(&jvm);
if (env == NULL) return 1;
jclass myClass = NULL;
jmethodID main = NULL;
myClass = env->FindClass("HelloWorld");
if (myClass != NULL)
main = env->GetStaticMethodID(myClass, "main", "([Ljava/lang/String;)V");
else
printf("Unable to find the requested class\n");
if (main != NULL)
{
env->CallStaticVoidMethod( myClass, main, " ");
}else printf("main method not found") ;
jvm->DestroyJavaVM();
return 0;
}
Now put create_vm function and main function into a single cpp file, include jni.h and compile it. I used MinGW on windows.
g++ -D_JNI_IMPLEMENTATION_ -I"C:\Program Files\Java\jdk1.6.0_32\include" -I"C:\Program Files\Java\jdk1.6.0_32\include\win32" hello.cpp -L"C:\Program Files\Java\jre6\bin\client" -ljvm -o hello.exe
Exection
Now if you run the created exe, you will get an error. jvm.dll not found .
Put C:\Program Files\Java\jre6\bin\client
in your PATH environment variable. Now you can
run the exe file.
Note: Don't displace the jvm.dll file.
Yes, you can call a Java function from C++ or C, but unless you're using something like COM or CORBA (or another 3rd-party tool that I'm probably not aware of) you'll have to do this in the context of JNI.
The whole procedure to call a Java method from native code is described in Chapter 4 in section 4.2 called "Calling Methods" in Sun's JNI guide pdf, which you can find here.
After coding above examples, you need to do some configuration on your project.
Steps to link the jvm.lib to your project in Visual Studio:
- Right click on the project -> properties.
- On the Properties dialog box, add jvm.lib under Linker->Input->AdditionalDependencies area.
- Lastly write jvm.lib path(like "C:\Program Files\Java\jdk1.7.0_60\lib") under Linker->General->AdditionalLibraryDirectories
After those steps, your project can link to jvm and work well.