JNI annoyances
I've been working on a JNI interface to the iXmatch matching engine. The matching engine API is geared to straight C programming - not Objective-C, not C++, just straight C. As such, it doesn't know much about exceptions, and it doesn't know beans about objects. It likes to shove around arrays of ints. Or better yet, single-precision floats typecast as ints (hey - here's 32 bits in a row, and that's all you need to know about!)
It also likes to return data structures via pointers - if I expect to get back up to 64K of text data, I need to malloc() 64Kchars, and tell the matching engine where to put the result, and how much space is available for it.
None of this maps well onto Java. So, we're tackling this in two steps. The first is to do a private Java class that exposes native methods that map as closely as possible onto the C code, and produce C-side JNI code for this. The second step will be to do a more usable public Java API that maps onto the private API.
The reason for this two-step dance is to let me do most of the marshalling work between the human-usable Java API and the C API in Java rather than in C. This is important, because the JNI interfaces for dealing with java data structures from C are painful at best.
One thing that does want to happen in C, however, is some final validation of data before things are passed off to the engine itself. The Java-appropriate thing to do if these validation tests fail is to throw an exception back to the caller. One would like to be able to write something like:
env->throw("java.lang.InvalidArgumentException", "bogus parameter");
but you don't get to do that. Since java exceptions are classes, you need to get a handle to the class object for the exception you want to throw, and then you can throw it.
This makes the exception handling code uglier than it needs to be, until you write something like the following:
/*
JNI doesn't make it easy to throw an exception,
so this utility method might help.
Throws an exception back to the VM, of the type passed in
via 'className', and with the message specified in 'message'.
If the exception class named 'className' isn't found,
then throw a java.lang.ClassDefNotFoundError
exception back to the caller.
*/
jobject throwException(JNIEnv *env, const char *className, const char *message)
{
jclass exc = env->FindClass(className);
if (exc != NULL)
{
env->ThrowNew(exc, message);
}
env->DeleteLocalRef(exc);
return NULL;
}
which is fine, and a reasonable thing to write, but it seems to be that EVERYONE who has to write JNI code is going to have to write that sort of function. Why isn't it part of JNI itself? And if, god forbid, you want to throw a chained exception, you have to go find the method ID of the constructor of the exception you want to throw, create it, and then pass it to throw, checking for exceptions all along the way. Painful painful painful.


0 Comments:
Post a Comment
Links to this post:
Create a Link
<< Home