Spontaneously Call Java from C++

jSegue requires a IRMIFL::jni_env pointer for all JNI operations. Anywhere a JNI call defines JNIEnv *as a parameter it is safe to substitute jni_env instead because jni_env is designed to be cast from a JNIEnv pointer. If you already have a JNIEnv pointer you can use the jni_env *jni_cast(JNIEnv *) function. The form static_cast<jni_env *>(JNIEnv *) was considered, but we ended up making jni_env privatly derive from JNIEnv so that the unchecked methods of JNIEnv are hidden.

jSegue thunk methods wrap jSegue impl methods with a try/catch block so that any java::lang::Throwable * derived exception is caught and returned to the JVM. jSegue impl methods are passed a jni_env pointer as their first parameter in a similar way that JNI calls normally pass JNIEnv pointer.

When a "spontaneous" JNI call must be made there are two options for obtaining a jni_env pointer. The recommended way is to declare an auto (local) variable of the type IRMIFL::jni_local_frame, and then calling its setup() method, storing the return value into an IRMIFL::jni_env *. The local reference frame is popped in ~jni_local_frame, so that when the jni_local_frame variable goes out of scope all local reference are deleted.

Additionally, when using a jni_local_frame its a good practice to declare a try/catch block so that any java exceptions that have been converted to C++ exceptions can be caught and reported. In the spontaneous call case these cannot be propagated back to java, but you can use java.util.logging.Logger or JNIEnv::ExceptionDescribe to log the exception, including its stack trace. This sample from OleThread.cpp:

    IRMIFL::jni_local_frame lf;
    IRMIFL::jni_env &env = *lf.setup(lf);
    try {
        global_event->dispatch(env);
    } catch (Throwable *t) {
        env.throw_object(t);
        env.exception_describe();
        env.exception_clear();
    }
Note however, the following code has a serious problem:
    if (a_problem_exists) {
        IRMIFL::jni_local_frame lf;
        throw new(lf.get_env()) RuntimeException(lf.get_env(), "A problem exists");
    }

The problem is that the RuntimeException will be referenced by a JNI local reference that will get deleted when lf variable goes out of scope. So this code will throw a local reference that will be deleted before the exception propagates to the next stack frame.


$Id: spontaneous.html 3769 2007-06-08 19:06:43Z hastings $