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.