views:

847

answers:

1

I'd like a consistent and simple way to throw exceptions in JNI code; something that handles chained exceptions (implicitly from the env->ExceptionOccurred method, or explicitly by parameters, either way is good) and saves me looking up constructors every time I want to do this. All of the above is preferably in C, although I could translate it from C++ at need.

Does anyone on SO have something like this that they can share?

+2  A: 

We just code utility methods for each of the types of exceptions we want to throw. Here are some examples:

jint
throwNoClassDefError( JNIEnv *env, char *message )

{
jclass   exClass;
char  *className = "java/lang/NoClassDefFoundError" ;

exClass = (*env)->FindClass( env, className );
if ( exClass == NULL )
 {
 return throwNoClassDefError( env, className );
 }

return (*env)->ThrowNew( env, exClass, message );
}

jint
throwNoSuchMethodError(

 JNIEnv *env, char *className, char *methodName, char *signature )
{
jclass   exClass;
char  *exClassName = "java/lang/NoSuchMethodError" ;
LPTSTR   msgBuf;
jint   retCode;
size_t   nMallocSize;

exClass = (*env)->FindClass( env, exClassName );
if ( exClass == NULL )
 {
 return throwNoClassDefError( env, exClassName );
 }

nMallocSize = strlen(className) 
 + strlen(methodName)
 + strlen(signature) + 8;

msgBuf = malloc( nMallocSize );
if ( msgBuf == NULL )
 {
 return throwOutOfMemoryError
  ( env, "throwNoSuchMethodError: allocating msgBuf" );
 }
memset( msgBuf, 0, nMallocSize );

strcpy( msgBuf, className );
strcat( msgBuf, "." );
strcat( msgBuf, methodName );
strcat( msgBuf, "." );
strcat( msgBuf, signature );

retCode = (*env)->ThrowNew( env, exClass, msgBuf );
free ( msgBuf );
return retCode;
}

jint
throwNoSuchFieldError( JNIEnv *env, char *message )

{
jclass   exClass;
char  *className = "java/lang/NoSuchFieldError" ;

exClass = (*env)->FindClass( env, className );
if ( exClass == NULL )
 {
 return throwNoClassDefError( env, className );
 }

return (*env)->ThrowNew( env, exClass, message );
}

jint
throwOutOfMemoryError( JNIEnv *env, char *message )

{
jclass   exClass;
char  *className = "java/lang/OutOfMemoryError" ;

exClass = (*env)->FindClass( env, className );
if ( exClass == NULL )
 {
 return throwNoClassDefError( env, className );
 }

return (*env)->ThrowNew( env, exClass, message );
}

That way, it's easy to find them, your code-completion editor will help you to type them in, and you can pass simple parameters.

I'm sure you could expand this to handle chained exceptions, or other more complicated approaches. This was enough to meet our needs.

Steven M. Cherry
Just found this, thanks. However, won't the error condition in `throwNoClassDefError` result in infinite recursion and an inevitable stack overflow? It should really never happen, I admit, but that doesn't seem like the appropriate way to handle it. Perhaps fall back on `java.lang.error`, and `abort()` or something if that doesn't work.
Tim Sylvester