Search code examples
javacjava-native-interface

Calling a Java Method from the native code using jni


I am new at using JNI. I successfully write a few programs that call native methods written in c.

Now I need my java code to be called by the native code side after it is initialized. Is it possible? Until now, I tried some kind of polling techniques. That is, I check native code parameters from my java code periodically, but if there is a way that native code can send some kind of interrupt it could be more efficient. Is it possible? Or can you suggest a better way than polling?

Note: When I search for "Call Java Functions from C Using JNI" all the answers I get is like

http://www.codeproject.com/Articles/22881/How-to-Call-Java-Functions-from-C-Using-JNI

JNI Call java method from c program

Those examples is not an answer for my situation. Because my main program is in java, and what I ask is that: Can the native functions(written in c) that I call from java code call some other java functions under certain circumstances? Is it possible to manage this without using a polling technique like I mentioned above?


Solution

  • Sure. It is actually easier than in the examples you linked because you don't have to spawn a JVM to do it -- the java functions that call you give you a pointer to the environment that you can use. As a simple example: With a Java class like this:

    public class foo {
      static {
        // load libfoo.so / foo.dll
        System.loadLibrary("foo");
      }
      
      private native void nativecall();
      
      public static void main(String[] args) {
        foo f = new foo();
    
        f.nativecall();
      }
    
      public void callback() {
        System.out.println("callback");
      }
    
      public static void callback_static() {
        System.out.println("static callback");
      }
    }
    

    And a library compiled from C code like this:

    #include <jni.h>
    
    JNIEXPORT void JNICALL Java_foo_nativecall(JNIEnv *env, jobject foo_obj) {
      // Get the class from the object we got passed in
      jclass cls_foo = (*env)->GetObjectClass(env, foo_obj);
    
      // get the method IDs from that class
      jmethodID mid_callback        = (*env)->GetMethodID      (env, cls_foo, "callback"       , "()V");
      jmethodID mid_callback_static = (*env)->GetStaticMethodID(env, cls_foo, "callback_static", "()V");
    
      // then call them.
      (*env)->CallVoidMethod      (env, foo_obj, mid_callback);
      (*env)->CallStaticVoidMethod(env, cls_foo, mid_callback_static);
    }
    

    you would get the output

    callback
    static callback
    

    If you don't get an object of the class you want to work with, you can use the FindClass and NewObject functions to make one, as in

    jclass    cls_foo  = (*env)->FindClass  (env, "foo");
    jmethodID ctor_foo = (*env)->GetMethodID(env, cls_foo, "<init>", "()V");
    jobject   foo_obj  = (*env)->NewObject  (env, cls_foo, ctor_foo);