Exception handling

Exception test examples:


public native void testException1(a);

public static void main(String[] args) {

    JniTest test = new JniTest();

    try {
        test.testException();
        System.out.println("Program cannot continue 1, this sentence will not be printed \n");
    } catch (Throwable t) {
        System.out.println("Catch an exception thrown by JNI (Throwable), this will be printed" + t.getMessage() + "\n");
    }

    System.out.println("The program continues to execute 2, and the sentence will be printed \n");

}
Copy the code

C code is as follows:


// Exception handling
JNIEXPORT void JNICALL Java_com_test_JniTest_testException1
(JNIEnv * env, jobject jobj){

    jclass clz=  (*env)->GetObjectClass(env, jobj);
    // The property name was incorrectly written, and the property name was empty
    jfieldID fid = (*env)->GetFieldID(env, clz, "key1"."Ljava/lang/String;");

    // This throws an exception that Java can catch through Throwable

    printf("C can run , this will print");
    // It is possible to continue execution
    jstring key =  (*env)->GetObjectField(env, jobj, fid);
    // The C program crashed
    char* c_str = (*env)->GetStringUTFChars(env, key, NULL);
    printf("C could not run , this will not print");
}
Copy the code

As you can see from the examples, the JNI layer throws an exception of the Error type. Java can catch the exception through Throwable or Error. After catching the exception, Java code can continue to execute.

In order to ensure that Java, C/C++ code can execute properly, you need to:

Manually clear ExceptionClear in the JNI layer to ensure that the code can run. Remedies ensure that C/C++ code continues to run. Such as:


// Exception handling
JNIEXPORT void JNICALL Java_com_test_JniTest_testException1
(JNIEnv * env, jobject jobj){
    jclass clz = (*env)->GetObjectClass(env, jobj);
    // The property name was incorrectly written, and the property name was empty
    jfieldID fid = (*env)->GetFieldID(env, clz, "key1"."Ljava/lang/String;");

    jthrowable err = (*env)->ExceptionOccurred(env);
    if(err ! =NULL) {// Manually clear the exception information to ensure that the Java code can continue to execute
        (*env)->ExceptionClear(env);
        // Provide a remedy, such as getting another property
        fid = (*env)->GetFieldID(env, clz, "key"."Ljava/lang/String;");
    }


    jstring key = (*env)->GetObjectField(env, jobj, fid);
    char* c_str = (*env)->GetStringUTFChars(env, key, NULL);
}
Copy the code

The test code is as follows:


public static void main(String[] args) {

    JniTest test = new JniTest();

    try {
        test.testException();
        System.out.println("There is no exception in the program, this sentence will be printed \n");
    } catch (Exception e) {
        System.out.println("No exception thrown by JNI was caught, this sentence will not be printed" + e.getMessage() + "\n");
    }

    System.out.println("Program continues, this sentence will be printed \n");

}
Copy the code

The user can manually throw an exception through the ThrowNew function, which can also be caught by Java code:


// Exception handling
JNIEXPORT void JNICALL Java_com_test_JniTest_testException
(JNIEnv * env, jobject jobj){
    jclass clz = (*env)->GetObjectClass(env, jobj);
    // The property name was incorrectly written, and the property name was empty
    jfieldID fid = (*env)->GetFieldID(env, clz, "key1"."Ljava/lang/String;");

    jthrowable err = (*env)->ExceptionOccurred(env);
    if(err ! =NULL) {// Manually clear the exception information to ensure that the Java code can continue to execute
        (*env)->ExceptionClear(env);
        // Provide a remedy, such as getting another property
        fid = (*env)->GetFieldID(env, clz, "key"."Ljava/lang/String;");
    }


    jstring key = (*env)->GetObjectField(env, jobj, fid);
    char* c_str = (*env)->GetStringUTFChars(env, key, NULL);

    // The argument is not correct. The programmer throws an exception, which can be caught in Java
    if (_stricmp(c_str,"efg") != 0){
        jclass err_clz = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
        (*env)->ThrowNew(env, err_clz, "key value is invalid!"); }}Copy the code

The test code is as follows:


public static void main(String[] args) {

    JniTest test = new JniTest(a);try {
        test.testException(a); System.out.println("JNI manually threw an exception, Java will not continue, this sentence will not be printed \n");
    } catch (Exception e) {
        System.out.println("Caught an exception that JNI manually threw, this sentence will be printed:" + e.getMessage() + "\n");
    }

    System.out.println("Program continues, this sentence will be printed \n");

}
Copy the code

Summary of Exception Handling

JNI throws an exception of the Error type, which Java can catch through Throwable or Error. After catching an exception, Java code can continue to execute. At the C layer, ExceptionClear is allowed to ensure that the Java code in the try continues to execute, and it is best to provide a remedy to ensure that the JNI layer code continues to run normally. Exceptions thrown manually by the user through ThrowNew can also be caught in the Java layer.