Search code examples
javaexceptionjava-native-interface

Best way to throw exceptions in JNI code?


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?


Solution

  • 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.