Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JNI - Listener in C++/Java - is it possible to instantiate Java objects in c++ and use them as parameters

Is the following usable with JNI?

public NativeClass {

    static {
        System.loadLibrary("dll");
    }

    public static native void addListener(Listener listener);
}

public interface Listener {
    public void eventOccurred(Info info);
}

public Info {

    private final String s1;
    private final String s2;

    public Info(String s1, String s2);

    // ... getters for use in Java
}

Is it possible to

  • register a Listener object on a dll (should be no problem, as far as I found out)
  • instantiate an Info object in the c/c++ code and use it as a parameter for calling Listener.eventOccured(Info...)?

Or what would be a good way to implement a listener which gets some information from a DLL?

In my case - we have a dll wich does some work. We call this dll from java. Now we want to attach a listener to the dll, to push us some progress information while working. The above example is the listener part, which I don't know if it is possible regarding the constructor call to a Java constructor from c/c++.

A hint where to find a piece of documentation, which describes the answer would be nice - I could not find infos, which answered my question.

A small snippet of code, describing the c/c++ part would be the icing on the cake :)

like image 818
Kai Mechel Avatar asked Mar 21 '23 02:03

Kai Mechel


1 Answers

The short answer is yes, you can hold, instantiate, and pass Java objects in a native layer via JNI.

In the jni documentation, you will find functions that will do this for you. http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html

You will also Use javap -s and javah to assist in finding your java method signatures for use in jni and to make your jni headers. See http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javap.html & http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javah.html

Here is a sample of what you will be doing. I haven't tested it, so just use it as a reference for writing your own. Note: be aware of package notations(I've assumed no package) & Exceptions. Exceptions can happen on any JNI call(env->...), so check the documentation on how to deal with exceptions(ExceptionCheck, ExceptionDescribe, ExceptionClear).

JavaVM * savedVM = NULL;
JNIEXPORT void JNICALL Java_NativeClass_addListener(JNIEnv *env, jobject obj_instance, jobject listener_instance) 
{
   env->GetJavaVM( &savedVM );
   //save listener_instance for use later
   saved_listener_instance = listener_instance;
}

void doSomething()
{
    //Get current thread JNIEnv
    JNIEnv * ENV;
    int stat = savedVM->GetEnv((void **)&ENV, JNI_VERSION_1_6);
    if (stat == JNI_EDETACHED)  //We are on a different thread, attach
        savedVM->AttachCurrentThread((void **) &ENV, NULL);
    if( ENV == NULL )
        return;  //Cant attach to java, bail

    //Get the Listener class reference
    jclass listenerClassRef = ENV->GetObjectClass( saved_listener_instance );

    //Use Listener class reference to load the eventOccurred method
    jmethodID listenerEventOccured = ENV->GetMethodID( listenerClassRef, "eventOccurred", "(LInfo;)V" );

    //Get Info class reference
    jclass infoClsRef = ENV->FindClass( "Info" );

    //Create Info class
    jobject info_instance = ENV->NewObject( infoClsRef, ..... );//For you to fill in with your arguments

    //invoke listener eventOccurred
    ENV->CallVoidMethod( saved_listener_instance, listenerEventOccured, info_instance );

    //Cleanup
    ENV->DeleteLocalRef( info_instance );
}
like image 190
Samhain Avatar answered Mar 22 '23 14:03

Samhain