All examples I've found so far for calling a Java function from C, show how to first create/start a JVM from C. But In my case, the application starts from Java and the C function is called from Java.
Is it possible, for instance, to create a "native" method implemented in C, and to use it in order to save the JNIEnv
pointer, and then to reuse it, instead of creating a new JVM instance from C, in order to call Java methods?
Is there an example for it?
EDIT:
The question above is based on a misunderstanding. Every native method (A Java method implemented in C) is supplied with an up-tp-date JNIEnv
pointer as a part of its signature. This is the only JNIEnv pointer that should be used for calling Java methods from a native method.
Caching and using an old saved JNIEnv pointer could in the best scenario crash your application. In worse scenarios, it might cause low-level inconsistency problems that are very hard to debug and understand.
As JJF stated, this is definitely possible! I'll show an example below, assuming you already know how to call Java methods from C, but without having to create a JVM!
First, we have a Java class test.Test.java
that calls the native method methodA
:
package test;
public class Test {
static {
System.loadLibrary("test");
}
private native void methodA();
public static void methodB() {
System.out.println("Java: Method B has executed!");
}
public static void main(String[] args) {
new Test().methodA();
}
}
Next, we have the header file created by javah
or javac -h
:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_Test */
#ifndef _Included_test_Test
#define _Included_test_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: test_Test
* Method: methodA
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_test_Test_methodA
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Below is the C file which holds the native method methodA
:
#include <jni.h>
#include <stdio.h>
#include "test_Test.h"
void callMethodB(JNIEnv *env);
JNIEXPORT void JNICALL Java_test_Test_methodA(JNIEnv *env, jobject thisObj) {
printf("C: Method A executed!\n"); fflush(stdout);
callMethodB(env);
return;
}
void callMethodB(JNIEnv *env) {
jclass testClass = (*env) -> FindClass(env, "test/Test");
jmethodID methodB = (*env) -> GetStaticMethodID(env, testClass, "methodB", "()V");
(*env) -> CallStaticVoidMethod(env, testClass, methodB, NULL);
return;
}
The output of this program is:
C: Method A executed!
Java: Method B has executed!
Remember to create a test.dll
file with your preferred GNU compiler.