Reputation: 51
I want to call a C funcion from Java using JNI. And in the C function, I want to create a JVM and call some Java objects. When I try to create the JVM, JNI_CreateJavaVM returns -1.
So, I want to know if it is possible to do this. The C code is compiled to create a .so file (in linux), and the Java code calls the function in the .so file.
Any example doing Java->C->Java will be useful.
Thanks.
Upvotes: 5
Views: 459
Reputation: 8203
I can't see why some people consider this useless. In fact, the Java -> C -> Java scenario is very common when you get into Android game programming:
The reason why it is necessary to use the SDK (Java) is that most of the Android APIs are provided only in Java! The NDK (C / C++) only provides a slim Linux environment (think it as "Standard C Library" + "Standard C++ Library" + "Cutdown Version of Linux System Libraries"). For example, if you want to integrate your app with AdMob (Google Ads), or In-app Billing (Google Payment), or if you want to access the built-in camera of the device, you have to invoke Java methods from the game logic (which is written is C / C++!).
Write a Java class. Declare one method native
:
$ ls -F1
classes/
jni/
src/
$ nano src/com/example/jcj/Test.java
Test.java:
package com.example.jcj;
public class Test {
public static void main(String[] args) {
doSomethingInC();
}
public static native void doSomethingInC();
public static void doSomethingInJava() {
System.out.println("Done something in Java!");
}
static {
System.loadLibrary("hello_jcj");
}
}
Invoke the "Java compiler" (javac
), followed by the "C header and stub file generator" (javah
):
$ javac -sourcepath src -d classes src/com/example/jcj/Test.java
$ javah -classpath classes -d jni com.example.jcj.Test
$ ls -F1 jni/
com_example_jcj_Test.h
Implement the C part:
$ nano jni/com_example_jcj_Test.c
com_example_jcj_Test.c:
#include "com_example_jcj_Test.h"
#include <stdio.h>
/*
* Class: com_example_jcj_Test
* Method: doSomethingInC
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_com_example_jcj_Test_doSomethingInC(JNIEnv* env, jclass clazz)
{
printf("Done something in C!\n");
}
Compile the C source (Windows):
> REM TODO: Add this!
Compile the C source (Linux):
$ gcc -I{JAVA_HOME}/include
-shared \
-o libhello_jcj.so \
jni/com_example_jcj_Test.c
$ ls -F1
classes/
jni/
libhello_jcj.so*
src/
Compile the C source (Mac OS X):
$ gcc -I${JAVA_HOME}/include \
-shared \
-o libhello_jcj.jnilib \
jni/com_example_jcj_Test.c
$ ls -F1
classes/
jni/
libhello_jcj.jnilib*
src/
Run the Java application:
$ java -classpath classes com.example.jcj.Test
Done something in C!
Since you started your program in Java (instead of in C / C++), a JVM is already created. You don't need to create another one in the second part (C -> Java part), you just need to reuse the one already created. There are 2 ways to do it:
JNIEnv*
) provided by the JNI call from the first part (Java -> C part)JavaVM*
) saved during JNI_OnLoad()
(The answer is not finished and I will finish it later. If you like it, please vote me up for encouragement. Thanks!)
References:
Upvotes: 1
Reputation: 4952
Why do you need to create a second JVM? You can't create a second JVM, but you can access Java classes from C code. See Accessing Java Objects.
Upvotes: 2
Reputation: 13728
I can not see the point in that Java-->C-->Java.
If you can call C from Java, then you can call Java from Java after your C function returns.
Excelsion xFunction is an easy and reliable library for calling C from Java. It handles the weird JNI stuff giving you a simpler interface.
Upvotes: 2
Reputation: 559
No, unfortunately its not possible. You can only have one JVM per process, and you're already in a JVM process.
Upvotes: 2