Java Jni wrapping a simple callback machanism

Here we’re going to look at a very simple callback in C an how you might wrap it for Java. Let’s dive straight in with some example code

JNIEXPORT void JNICALL Java_Bogus_setCallback
  (JNIEnv *e, jclass c, jobject inst, jstring method) 
{
    const char *cbn = (*e)->GetStringUTFChars(e, method, 0);
    bcbclass = (*e)->GetObjectClass(e, inst);
    bcbmethod = (*e)->GetMethodID(e, bcbclass, cbn, "(III)V");
    (*e)->ReleaseStringUTFChars(e, method, cbn);  
    bcbe=e;
    if (bcbmethod == 0) return;
    BogusSetCallback(bogusCallBack);
      
}

We’re using a class instance and a method name to identify where the callback method is, additionally we’re caching the object class and method id, even if you’re not caching this info its still a good idea to do a dry run on the method id here, as if something is wrong with the method name JNI will issue an exception (which is why we return without need of error message) – WAIT…. JNI causing an exception – what no throwing the dummy out the pram seg fault behaviour…. I know shocking!

Don’t forget you can always use javap to help determine what the method signature should be.

Internally to our wrapper we will need a C function to actually receive the callback and dispatch it off to our Java version

void bogusCallBack(int a, int b, int c)
{
 (*bcbe)->CallVoidMethod(bcbe, bcbclass, bcbmethod, a, b, c);
}

So we have a number of cached values here that if you need a callback per C “object” you’ll need to lookup on the fly. bcbclass being the instance class and bcbmethod being the method ID.  If the library you’re wrapping is multi-threaded you’ll need to read up on attach thread take a look at the documentation here

Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *